Again closing frames and application

Hello,

I've got a problem regarding closing of frames and appliation too.
Attached to this mail you'll find a small sample application to
reproduce the situation.

My application creates a number of frames (from xml). When a frame gets
closed it will be hidden only so the app can show it later again (if
needed). If the last frame has been hidden the application destroys all
frames and so quits. This works fine until the question dialog appears.

Ok, when a frame gets hidden the app checks if there are pending
(unsaved) changes. If so, a dialog appears asking wether they should be
saved or not. After this dialog has been answered, the frame hides (and
it gets destroyed) but the main loop will *not* be stopped. If there is
no such dialog (in our sample-code the text-entry is empty) the main
loop gets terminated as expected.

The sample application is quite simple. If the text-entry widget is
left empty, the frame is "clean", which means no dialog will appear on
closing the frame (either by menu or via X-button). If the text-entry
widget is not empty, the dialog appears and the appication's main loop
won't get terminated after closing the frame.

If we uncomment the line "event.GetEventObject().Show()" in the method
"OnCloseWindow", the main loop terminates as expected even if a dialog
apears.

Why do I need to add that Show() ? Does it make sense, or is it a bug?

Thanks for your help,

Johannes

closing.py (3.69 KB)

···

--
BYTEWISE Software GmbH Tel +43 (5577) 89877-0
i.A. Johannes Vetter Fax +43 (5577) 89877-66
A-6890 Lustenau, Enga 2 http://www.bytewise.at
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Wir bieten Installation und Support für Ubuntu: ein auf
GNU/Linux basierendes Softwaresystem für Arbeitsplatzrechner

Hi Johannes,

Johannes Vetter wrote:

Hello,

I've got a problem regarding closing of frames and appliation too.
Attached to this mail you'll find a small sample application to
reproduce the situation.

My application creates a number of frames (from xml). When a frame gets
closed it will be hidden only so the app can show it later again (if
needed). If the last frame has been hidden the application destroys all
frames and so quits. This works fine until the question dialog appears.

Ok, when a frame gets hidden the app checks if there are pending
(unsaved) changes. If so, a dialog appears asking wether they should be
saved or not. After this dialog has been answered, the frame hides (and
it gets destroyed) but the main loop will *not* be stopped. If there is
no such dialog (in our sample-code the text-entry is empty) the main
loop gets terminated as expected.

The sample application is quite simple. If the text-entry widget is
left empty, the frame is "clean", which means no dialog will appear on
closing the frame (either by menu or via X-button). If the text-entry
widget is not empty, the dialog appears and the appication's main loop
won't get terminated after closing the frame.

If we uncomment the line "event.GetEventObject().Show()" in the method
"OnCloseWindow", the main loop terminates as expected even if a dialog
apears.

Why do I need to add that Show() ? Does it make sense, or is it a bug?

For what it is worse, for me your sample closes correctly without having to use your work around. (on Windows XP, Python 2.4 and wxPython 2.6.3.3

Werner

···

Thanks for your help,

Johannes

------------------------------------------------------------------------

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Closing frames and exiting the application

import wx

# =============================================================================
# Sample frame class
# =============================================================================

class MyFrame(wx.Frame):

   def __init__(self):
       wx.Frame.__init__(self, None, -1, "Testing ...")

       self.CreateStatusBar()

       mainmenu = wx.MenuBar()
       menu = wx.Menu()
       menu.Append(wx.ID_EXIT, 'E&xit\tCtrl+Q', 'Get the heck outta here!')
       mainmenu.Append(menu, "&File")
       self.SetMenuBar(mainmenu)

       self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT)
       self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

       sizer = wx.BoxSizer(wx.VERTICAL)
       self.txt = wx.TextCtrl(self, -1)
       sizer.Add(self.txt, 0, wx.EXPAND | wx.ALL, 10)

       self.SetSizerAndFit(sizer)
       self.txt.SetFocus()
       self.Show()

   # -------------------------------------------------------------------------

   def OnCloseWindow(self, event):
       """ wx.EVT_CLOSE handler """

       print "OnCloseWindow"
       if event.CanVeto():
           print "CanVeto"
           event.Veto()
           self.deferred_close()
       else:
           print "No Veto allowed, so just do what has to be done"
           # FIXME: if we uncomment the following line, everything works fine.
           # But why is it needed ?
           # event.GetEventObject().Show()
           event.Skip()

   # -------------------------------------------------------------------------

   def OnExit(self, event):
       """ Event handler for wx.EVT_MENU (with wx.ID_EXIT) """

       print "ON-EXIT called from Menu"
       self.deferred_close()

   # -------------------------------------------------------------------------

   def deferred_close(self):
       """ check wether the user has unsaved data ... """

       print "DeferredClose: checking wether user has unsaved stuff ..."
       if self.txt.GetValue() != '' and self.__ask() is None:
           return

       self._ui_close_()
       self.maybe_exit()

   # -------------------------------------------------------------------------

   def maybe_exit(self):
       """ If no other frames are open close the application """

       print "Check if there are other windows open, otherwise exit!"
       # Usually we would iterate over all frames of an application here, but
       # for simplification we just close this one
       self.Close(True)

   # -------------------------------------------------------------------------

   def _ui_close_(self):
       """
       'close' this frame. Our application will only hide frames instead of
       closing them, since it might reuse them later and re-instanciating is
       not an option.
       """

       print "_ui_close_ will only hide this frame (for later reuse)"
       self.Hide()

   # -------------------------------------------------------------------------

   def __ask(self):
       """ helper method showing a simple question dialog """

       dlg = wx.MessageDialog(self, 'Wanna save stuff?', 'A Question',
               wx.YES_NO | wx.CANCEL)
       try:
           result = dlg.ShowModal()
       finally:
           dlg.Destroy()

       if result in [wx.ID_YES, wx.ID_NO]:
           return result == wx.ID_YES
       else:
           return None

# =============================================================================

if __name__ == '__main__':
   app = wx.PySimpleApp()
   f = MyFrame()
   app.MainLoop()
   print "GONE!"

Hi Werner,

I'm using GTK2 python 2.4.3 and wx 2.6.1.2pre (unicode) [on ubuntu
dapper].

I've checked with a wxMSW on XP running a python 2.3.4 with wx 2.6.1.0
and there it is working as intended. So it appears to be something
gtk-special.

Thanks,
Johannes

···

--
BYTEWISE Software GmbH Tel +43 (5577) 89877-0
i.A. Johannes Vetter Fax +43 (5577) 89877-66
A-6890 Lustenau, Enga 2 http://www.bytewise.at
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Wir bieten Installation und Support für Ubuntu: ein auf
GNU/Linux basierendes Softwaresystem für Arbeitsplatzrechner

Johannes Vetter wrote:

Hi Werner,

I'm using GTK2 python 2.4.3 and wx 2.6.1.2pre (unicode) [on ubuntu
dapper].

I've checked with a wxMSW on XP running a python 2.3.4 with wx 2.6.1.0
and there it is working as intended. So it appears to be something
gtk-special.

IIRC there was some issue with close events not being delivered if the window is not "mapped", which in wx speak is the same as being shown.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!