Windows XP, 7: PyAssertionError at "Close group" or "Close all windows" (using genericmessagedialog)

Hi all,
I have just started using wxPython for a very small GUI (taskbar icon,
modeless popups, modal error messages and a logfile window).

Now I have the following problem:
If there are multiple modeless popups and
* they are closed by "Close group" (Windows XP) or by "Close all
    windows" (Windows 7) or
* one of those is closed in Windows 7 by red cross via taskbar
    (NOT by right-click and then close)
I get the following exception:

Traceback (most recent call last):
  File "C:\Users\chr\.virtualenvs\wx_try\lib\site-packages\wx-2.8-msw-
unicode\wx\lib\agw\genericmessagedialog.py", line 681, in OnCancel
    self.EndModal(wx.ID_CANCEL)
  File "C:\Users\chr\.virtualenvs\wx_try\lib\site-packages\wx-2.8-msw-
unicode\wx\_windows.py", line 715, in EndModal
    return _windows_.Dialog_EndModal(*args, **kwargs)
wx._core.PyAssertionError: C++ assertion "IsModal()" failed at ..\..
\src\msw\dialog.cpp(361) in wxDialog::EndModal(): EndModal() called
for non modal dialog

In fact there are only non modal dialogs when I get the error. As it
can be seen I am using wx.lib.agw.genericmessagedialog for my dialogs,
Python 2.7 and wxPython 2.8.12.0.

Other ways of closing dialogs or closing the app - after a modal error
message or by exiting over the taskbar menu I close all dialogs by
iterating over wx.GetTopLevelWindows() - does not lead to any errors.

Is there a way to solve this?

Thank you,
Christian

Options:

1. Use frames instead of non-modal dialogs.
2. Catch the dialog's EVT_CLOSE event and do self.Destroy in the handler
3. Override GMD's OnCancel and check IsModal before calling EndModal

···

On 7/21/11 4:28 AM, Christian Wutte wrote:

Hi all,
I have just started using wxPython for a very small GUI (taskbar icon,
modeless popups, modal error messages and a logfile window).

Now I have the following problem:
If there are multiple modeless popups and
* they are closed by "Close group" (Windows XP) or by "Close all
     windows" (Windows 7) or
* one of those is closed in Windows 7 by red cross via taskbar
     (NOT by right-click and then close)
I get the following exception:

Traceback (most recent call last):
   File "C:\Users\chr\.virtualenvs\wx_try\lib\site-packages\wx-2.8-msw-
unicode\wx\lib\agw\genericmessagedialog.py", line 681, in OnCancel
     self.EndModal(wx.ID_CANCEL)
   File "C:\Users\chr\.virtualenvs\wx_try\lib\site-packages\wx-2.8-msw-
unicode\wx\_windows.py", line 715, in EndModal
     return _windows_.Dialog_EndModal(*args, **kwargs)
wx._core.PyAssertionError: C++ assertion "IsModal()" failed at ..\..
\src\msw\dialog.cpp(361) in wxDialog::EndModal(): EndModal() called
for non modal dialog

In fact there are only non modal dialogs when I get the error. As it
can be seen I am using wx.lib.agw.genericmessagedialog for my dialogs,
Python 2.7 and wxPython 2.8.12.0.

Other ways of closing dialogs or closing the app - after a modal error
message or by exiting over the taskbar menu I close all dialogs by
iterating over wx.GetTopLevelWindows() - does not lead to any errors.

Is there a way to solve this?

--
Robin Dunn
Software Craftsman

I believe this is also screaming for a big patch to GMD... is it
enough to call self.Destroy() if the GMD is not modal to get rid of
this problem? Of course that would remove the usefulness of a possible
return value for GMD, as the call to:

self.EndModal(wx.ID_YES)

implicitly returns wx.ID_YES to the developers who is asking about a
return value from GMD...

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

==> Never *EVER* use RemovalGroup for your house removal. You'll
regret it forever.
The Doomed City: Removal Group: the nightmare <==

···

On 21 July 2011 18:53, Robin Dunn wrote:

On 7/21/11 4:28 AM, Christian Wutte wrote:

Hi all,
I have just started using wxPython for a very small GUI (taskbar icon,
modeless popups, modal error messages and a logfile window).

Now I have the following problem:
If there are multiple modeless popups and
* they are closed by "Close group" (Windows XP) or by "Close all
windows" (Windows 7) or
* one of those is closed in Windows 7 by red cross via taskbar
(NOT by right-click and then close)
I get the following exception:

Traceback (most recent call last):
File "C:\Users\chr\.virtualenvs\wx_try\lib\site-packages\wx-2.8-msw-
unicode\wx\lib\agw\genericmessagedialog.py", line 681, in OnCancel
self.EndModal(wx.ID_CANCEL)
File "C:\Users\chr\.virtualenvs\wx_try\lib\site-packages\wx-2.8-msw-
unicode\wx\_windows.py", line 715, in EndModal
return _windows_.Dialog_EndModal(*args, **kwargs)
wx._core.PyAssertionError: C++ assertion "IsModal()" failed at ..\..
\src\msw\dialog.cpp(361) in wxDialog::EndModal(): EndModal() called
for non modal dialog

In fact there are only non modal dialogs when I get the error. As it
can be seen I am using wx.lib.agw.genericmessagedialog for my dialogs,
Python 2.7 and wxPython 2.8.12.0.

Other ways of closing dialogs or closing the app - after a modal error
message or by exiting over the taskbar menu I close all dialogs by
iterating over wx.GetTopLevelWindows() - does not lead to any errors.

Is there a way to solve this?

Options:

1. Use frames instead of non-modal dialogs.
2. Catch the dialog's EVT_CLOSE event and do self.Destroy in the handler
3. Override GMD's OnCancel and check IsModal before calling EndModal

If the dialog is shown modally then EndModal will still work as expected and the value will be returned from ShowModal. If the dialog is not modal then there is nothing waiting for the value anyway because ShowModal was not used.

The issue in this case is that the default EVT_CLOSE handler basically just tries to send a wx.ID_CANCEL button event, and your handler unconditionally calls EndModal. It looks like the C++ dialog code has changed things around a bit and the default button handlers call a helper method that looks like this instead of calling EndModal directly:

void wxDialogBase::EndDialog(int rc)
{
     if ( IsModal() )
         EndModal(rc);
     else
         Hide();
}

I'm not sure I would have chosen to use Hide() there, but I guess since dialogs are supposed to be Destroyed by the user code when it is modal then it makes sense that they should when non-modal too.

···

On 7/21/11 1:57 PM, Andrea Gavana wrote:

On 21 July 2011 18:53, Robin Dunn wrote:

On 7/21/11 4:28 AM, Christian Wutte wrote:

Hi all,
I have just started using wxPython for a very small GUI (taskbar icon,
modeless popups, modal error messages and a logfile window).

Now I have the following problem:
If there are multiple modeless popups and
* they are closed by "Close group" (Windows XP) or by "Close all
     windows" (Windows 7) or
* one of those is closed in Windows 7 by red cross via taskbar
     (NOT by right-click and then close)
I get the following exception:

Traceback (most recent call last):
   File "C:\Users\chr\.virtualenvs\wx_try\lib\site-packages\wx-2.8-msw-
unicode\wx\lib\agw\genericmessagedialog.py", line 681, in OnCancel
     self.EndModal(wx.ID_CANCEL)
   File "C:\Users\chr\.virtualenvs\wx_try\lib\site-packages\wx-2.8-msw-
unicode\wx\_windows.py", line 715, in EndModal
     return _windows_.Dialog_EndModal(*args, **kwargs)
wx._core.PyAssertionError: C++ assertion "IsModal()" failed at ..\..
\src\msw\dialog.cpp(361) in wxDialog::EndModal(): EndModal() called
for non modal dialog

In fact there are only non modal dialogs when I get the error. As it
can be seen I am using wx.lib.agw.genericmessagedialog for my dialogs,
Python 2.7 and wxPython 2.8.12.0.

Other ways of closing dialogs or closing the app - after a modal error
message or by exiting over the taskbar menu I close all dialogs by
iterating over wx.GetTopLevelWindows() - does not lead to any errors.

Is there a way to solve this?

Options:

1. Use frames instead of non-modal dialogs.
2. Catch the dialog's EVT_CLOSE event and do self.Destroy in the handler
3. Override GMD's OnCancel and check IsModal before calling EndModal

I believe this is also screaming for a big patch to GMD... is it
enough to call self.Destroy() if the GMD is not modal to get rid of
this problem? Of course that would remove the usefulness of a possible
return value for GMD, as the call to:

self.EndModal(wx.ID_YES)

implicitly returns wx.ID_YES to the developers who is asking about a
return value from GMD...

--
Robin Dunn
Software Craftsman

Great, I did it with option 3 (GMD subclass for my non modal popups).
Thank you.

What I don't understand is, why this only happens in the "group/all
windows/special
Win7 close" case?
Since GMD.OnCancel() is also called when clicking on the close button,
but then
without an error.

Christian

···

On Jul 21, 5:53 pm, Robin Dunn <ro...@alldunn.com> wrote:

Options:

1. Use frames instead of non-modal dialogs.
2. Catch the dialog's EVT_CLOSE event and do self.Destroy in the handler
3. Override GMD's OnCancel and check IsModal before calling EndModal

I don't know. Perhaps some messages/events are being sent in a slightly different order in that case.

···

On 7/22/11 7:30 AM, Christian Wutte wrote:

On Jul 21, 5:53 pm, Robin Dunn<ro...@alldunn.com> wrote:

Options:

1. Use frames instead of non-modal dialogs.
2. Catch the dialog's EVT_CLOSE event and do self.Destroy in the handler
3. Override GMD's OnCancel and check IsModal before calling EndModal

Great, I did it with option 3 (GMD subclass for my non modal popups).
Thank you.

What I don't understand is, why this only happens in the "group/all
windows/special
Win7 close" case?

--
Robin Dunn
Software Craftsman

Hi,

Options:

1. Use frames instead of non-modal dialogs.
2. Catch the dialog's EVT_CLOSE event and do self.Destroy in the handler
3. Override GMD's OnCancel and check IsModal before calling EndModal

Great, I did it with option 3 (GMD subclass for my non modal popups).
Thank you.

What I don't understand is, why this only happens in the "group/all
windows/special
Win7 close" case?
Since GMD.OnCancel() is also called when clicking on the close button,
but then
without an error.

I have updated the GMD source in SVN, implementing the fix proposed by
Robin is this helper method:

    def EndDialog(self, rc):
        """
        Ends the L{GenericMessageDialog} life. This will be done
differently depending on
        the dialog modal/non-modal behaviour.

        :param `rc`: one of the ``wx.ID_YES``, ``wx.ID_NO``,
``wx.ID_OK``, ``wx.ID_CANCEL`` constants.

        :note: the `rc` parameter is unused if the dialog is not modal.
        """

        if self.IsModal():
            self.EndModal(rc)
        else:
            self.Hide()

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

==> Never *EVER* use RemovalGroup for your house removal. You'll
regret it forever.
The Doomed City: Removal Group: the nightmare <==

···

On 22 July 2011 17:30, Christian Wutte wrote:

On Jul 21, 5:53 pm, Robin Dunn <ro...@alldunn.com> wrote: