I am in the process of testing the Persistent framework for
wxPython widgets, and I have stumbled upon a couple of obscure
problems I have never seen before. Basically the strategy is:
1) A widget is registered with a central "persistent manager";
2) Depending on the widget kind (i.e., wx.TextCtrl, wx.ListCtrl,
wx.Frame and so on), a dedicated class is created to save the
user-changeable properties of the widget (i.e., the text for a
wx.TextCtrl, column sizes for wx.ListCtrl in report mode, position,
size, iconized, maximized for a wx.Frame);
3) All these dedicated classes are subclass of an "abstract" class,
which actually will tell to the central "persistent manager" to save
the widget properties when the widget is destroyed. To do this, the
abstract class does the following:
(a) In the __init__ method of the abstract class:
# self._window is the actual widget itself
self._window.Bind(wx.EVT_WINDOW_DESTROY, self.HandleDestroy)
(b) In the destroy event handler:
def HandleDestroy(self, event):
"""
Handles the wx.EVT_WINDOW_DESTROY events for our widget.
:param `event`: L{wx.WindowDestroyEvent} to be processed.
"""
event.Skip()
# only react to the destruction of this object itself, not of any of
# its children
if event.GetEventObject() == self._window:
# this will delete this object itself
PM.PersistenceManager.Get().SaveAndUnregister(self._window)
Now, everything seemed to work quite well for a while, but then a
couple of problems showed up:
1) wx.FilePickerCtrl and wx.DirPickerCtrl raise a MemoryError when I
handle their destroy event and I try to save their paths using the
SaveAndUnregister() method mentioned above;
2) wx.RadioBox spits out the following message and crashes the whole demo:
runtime error R6025
- pure virtual function call
3) Sometimes I get this assertion from wxWidgets:
12:37:56: Debug: ..\..\src\common\wincmn.cpp(319): assert
"GetChildren().GetCount() == 0" failed in
wxWindowBase::~wxWindowBase(): children not destroyed
Am I missing something? Am I doing bad things by using the
wx.EVT_WINDOW_DESTROY event to handle the saving of the widgets'
properties? Will an alternative approach like handling the saving of
widgets' properties during their toplevel parent wx.EVT_CLOSE method
work or am I (again) missing something?
Thank you for your suggestions.
Andrea.
"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/
http://thedoomedcity.blogspot.com/
Hi Andrea,
Capture the parent Frame CLOSE intead the widget destroy:
TopParent = self._window.GetTopLevelParent()
TopParent.Bind(wx.EVT_CLOSE, self.HandleDestroy)
Regards,
--
*****************************************
Oswaldo Hernández
oswaldo (@) soft-com (.) es
*****************************************
PD:
Antes de imprimir este mensaje, asegúrese de que es necesario.
El medio ambiente está en nuestra mano.
>
> Am I missing something? Am I doing bad things by using the
> wx.EVT_WINDOW_DESTROY event to handle the saving of the widgets'
> properties?
Yes. It varies a little by platform and also widget type, but it's
possible (and likely) that this event is not delivered until the widget
is already in the process of being destroyed, and so it's not safe to
access its properties. I think the intent of EVT_WINDOW_DESTROY is to
serve as a notification for the parent, rather than for the widget itself.
> Will an alternative approach like handling the saving of
> widgets' properties during their toplevel parent wx.EVT_CLOSE method
> work
Yes. Or you could allow the programmer to do it explicitly, have them
call some method of the mix-in class that will recursively search for
child widgets to be persisted. You may want to allow this mode (turning
off the automatic persistence) for greater flexibility even if you do
have an automated way that works good.
--
Robin Dunn
Software Craftsman
http://wxPython.org
2009/11/13 Robin Dunn:
This is what I ended up doing: at the moment it is the programmer
responsibility to call "SaveAndUnregister" when the main frame (or any
window they decide to destroy) is being closed, although any widget
property can be saved at any moment by simply calling
PersistentManager.Get().Save(theWindow).
I am finished with the PersistenceControls, I just wanted to generate
Sphinx docs for the library before releasing it. I'll do that on
Monday when I get back to work.
Thanks for the suggestions.