Destroy Modal Dialog Programmatically

Hi,

Here is the sample code.
Just run the gui5.py

My comments in pagebucket.py explain where the dialog was supposed to be destroyed.

Thanks for the help

pagebucket.py (1.61 KB)

gui5.py (605 Bytes)

Two problems:

1. When you use pubsub to send messages from a worker thread the message is received in the context of the worker thread, not the GUI thread. So you'll still need to do something to pass control over to the GUI thread in order to operate on the dialog. wx.CallAfter works well.

2. Since wx.MessageDialog is not a real wx.Dialog (it's just a wwrapper around the system's stock message dialog APIs) it doesn't respond to EndZModal or Destroy like you would expect. If you want to programatically close it you'll need to derive your own class from wx.Dialog to do it.

3. Once you do #2 then using EndModal will be the correct method to use.

···

On 7/13/10 9:44 AM, david wende wrote:

Hi,

Here is the sample code.
Just run the gui5.py

My comments in pagebucket.py explain where the dialog was supposed to be
destroyed.

--
Robin Dunn
Software Craftsman
http://wxPython.org

Hi,

> Hi,

> Here is the sample code.
> Just run the gui5.py

> My comments in pagebucket.py explain where the dialog was supposed to be
> destroyed.

Two problems:

1. When you use pubsub to send messages from a worker thread the message
is received in the context of the worker thread, not the GUI thread. So
you'll still need to do something to pass control over to the GUI thread
in order to operate on the dialog. wx.CallAfter works well.

2. Since wx.MessageDialog is not a real wx.Dialog (it's just a wwrapper
around the system's stock message dialog APIs) it doesn't respond to
EndZModal or Destroy like you would expect. If you want to
programatically close it you'll need to derive your own class from
wx.Dialog to do it.

3. Once you do #2 then using EndModal will be the correct method to use.

--
Robin Dunn
Software Craftsmanhttp://wxPython.org

Robin - I subclassed wx.Dialog and also used CallAfter. It's mostly
working now.
One (hopefully last) issue.
When I close the dialog NON-programmatically, i.e. with the Cancel
button that I
created manually in my class, I get a return code of 5101. Where does
this number come from?

Thanks a lot

···

On Jul 13, 8:41 pm, Robin Dunn <ro...@alldunn.com> wrote:

On 7/13/10 9:44 AM, david wende wrote:

Hi,

> Hi,

> Here is the sample code.
> Just run the gui5.py

> My comments in pagebucket.py explain where the dialog was supposed to be
> destroyed.

Two problems:

1. When you use pubsub to send messages from a worker thread the message
is received in the context of the worker thread, not the GUI thread. So
you'll still need to do something to pass control over to the GUI thread
in order to operate on the dialog. wx.CallAfter works well.

2. Since wx.MessageDialog is not a real wx.Dialog (it's just a wwrapper
around the system's stock message dialog APIs) it doesn't respond to
EndZModal or Destroy like you would expect. If you want to
programatically close it you'll need to derive your own class from
wx.Dialog to do it.

3. Once you do #2 then using EndModal will be the correct method to use.

--
Robin Dunn
Software Craftsmanhttp://wxPython.org

Robin - I subclassed wx.Dialog and also used CallAfter. It's mostly
working now.
One (hopefully last) issue.
When I close the dialog NON-programmatically, i.e. with the Cancel
button that I
created manually in my class, I get a return code of 5101. Where does
this number come from?

Thanks a lot

--

steven@dm-steven:~$ python
Python 2.6.4 (r264:75706, Dec 7 2009, 18:43:55)
[GCC 4.4.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.

import wx
wx.ID_CANCEL

5101

···

On 14 July 2010 11:16, dubiboy <david.wende@gmail.com> wrote:

On Jul 13, 8:41 pm, Robin Dunn <ro...@alldunn.com> wrote:

On 7/13/10 9:44 AM, david wende wrote:

PSB

···

On Jul 14, 3:38 pm, Steven Sproat <spro...@gmail.com> wrote:

On 14 July 2010 11:16, dubiboy <david.we...@gmail.com> wrote:

> Hi,

> On Jul 13, 8:41 pm, Robin Dunn <ro...@alldunn.com> wrote:
>> On 7/13/10 9:44 AM, david wende wrote:

>> > Hi,

>> > Here is the sample code.
>> > Just run the gui5.py

>> > My comments in pagebucket.py explain where the dialog was supposed to be
>> > destroyed.

>> Two problems:

>> 1. When you use pubsub to send messages from a worker thread the message
>> is received in the context of the worker thread, not the GUI thread. So
>> you'll still need to do something to pass control over to the GUI thread
>> in order to operate on the dialog. wx.CallAfter works well.

>> 2. Since wx.MessageDialog is not a real wx.Dialog (it's just a wwrapper
>> around the system's stock message dialog APIs) it doesn't respond to
>> EndZModal or Destroy like you would expect. If you want to
>> programatically close it you'll need to derive your own class from
>> wx.Dialog to do it.

>> 3. Once you do #2 then using EndModal will be the correct method to use.

>> --
>> Robin Dunn
>> Software Craftsmanhttp://wxPython.org

> Robin - I subclassed wx.Dialog and also used CallAfter. It's mostly
> working now.
> One (hopefully last) issue.
> When I close the dialog NON-programmatically, i.e. with the Cancel
> button that I
> created manually in my class, I get a return code of 5101. Where does
> this number come from?

> Thanks a lot

> --

steven@dm-steven:~$ python
Python 2.6.4 (r264:75706, Dec 7 2009, 18:43:55)
[GCC 4.4.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.

>>> import wx
>>> wx.ID_CANCEL
5101

Thanks Steven
Am I embarrassed! This should have been obvious to me.

It's the value passed to EndModal, and by common convention the ID of the button used to close the dialog is the value that is used. Support for handling wx.ID_OK and wx.ID_CANCEL buttons in dialogs is built-in.

···

On 7/14/10 5:38 AM, Steven Sproat wrote:

On 14 July 2010 11:16, dubiboy<david.wende@gmail.com> wrote:

Robin - I subclassed wx.Dialog and also used CallAfter. It's mostly
working now.
One (hopefully last) issue.
When I close the dialog NON-programmatically, i.e. with the Cancel
button that I
created manually in my class, I get a return code of 5101. Where does
this number come from?

Thanks a lot

--

steven@dm-steven:~$ python
Python 2.6.4 (r264:75706, Dec 7 2009, 18:43:55)
[GCC 4.4.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.

import wx
wx.ID_CANCEL

5101

--
Robin Dunn
Software Craftsman
http://wxPython.org

I try to do something very similar and tried to follow your suggestions. I keep getting the following error when I try to close the modal window:

wx._core.wxAssertionError: C++ assertion “IsModal()” failed at …\src\msw\dialog.cpp(197) in wxDialog::EndModal(): EndModal() called for non modal dialog

Here is a minimal example:

import wx

app = wx.App()
frame = wx.Frame(None, wx.ID_ANY, title="Hello World")
button = wx.Button(frame, wx.ID_ANY, 'Test')
with wx.FileDialog(frame, "Save XYZ file") as fileDialog:
    timer = wx.Timer()

    def close(event):
         wx.CallAfter(fileDialog.EndModal,wx.CANCEL)
         timer.Stop()

    timer.Bind(wx.EVT_TIMER, close)

    def onButton(event):
        timer.Start(100)

        fileDialog.ShowModal()
        print("finished")

    button.Bind(wx.EVT_BUTTON, onButton)
    frame.Show(True)
    loop = app.MainLoop()

Can anyone see what I’m doing wrong?

Thanks

I ran your code using Python 3.10.6 + wxPython 4.2.0 gtk3 (phoenix) wxWidgets 3.2.0 + Linux Mint 21 and didn’t get any errors.

Thanks for the quick reply. I’m also running 4.2.0 but I’m on Windows.

Just to make sure because I forgot to write instructions: You clicked on the button in the frame and the FileDialog opened and closed?

Yes. Initially when I clicked the button there was just a brief flash so I couldn’t tell what had happened. When I increased the timer delay from 100 to 1000, it was clear that the file dialog was being displayed and then closed.

Indeed it is working as expected on my Linux machine as well (CentOS 7, wxPython 4.1.1, python 3.6.8) Let me try on windows with a different python version.

Sidenote: I simply installed on windows with “pip install wxPython”. Anything wrong with that?

On Windows the wx.FileDialog is not a true wx.Dialog but just a wrapper around a system API, so EndModal has no meaning for it. If you create your own dialog class derived from wx.Dialog then things should work as you expect.

1 Like

Thanks for the answer, that makes sense. I’m using traitsui which is a wrapper around wxPython, which uses wx.FileDialog under the hood. If possible I would like to stick to the wx.FileDialog. Is there a way to close the wx.FileDialog programatically? I tried to call Close() and Destroy() but it looks like they have no effect.

Can you explain why you need to be able to programatically close the file dialog? Maybe we can suggest something that will also work for your needs.

For example, in a use case I can think of for wanting to do something like this (not blocking forever if the user is not sitting at their computer at the time) I would use a normal wx.Dialog with a message and a “Save Now” button that launches the file dialog when clicked, and which will time-out and call EndModal from a timer handler if the user isn’t there to do anything with it.

In my use case there is a separate thread that receives messages from another application (very similar to the original example of the question). For some messages, all windows except the main window need to be closed. I used the wx.Timer in the example just to keep the example simpler.