When is Unbind() recommended/required?

When is wx.EvtHandler.Unbind() recommended/required?

I am attempting maintenence of an application where users interact with hundreds
of controls per virtual page (implemented as a wx.Panel), and with scores of
such pages. Apparently some users must run other resource-intensive applications
concurrently, reportedly hitting the platform-specific (Windows XP) limit of 64k
native window objects. Reconfiguration of user kernels is not an acceptable
workaround.

I propose changing the application to instantiate panels only when they are
viewed, and then wx.Window.Destroy() them - instead of wx.Window.Hide() them -
when they are not in the users' view. But I cannot find an overview describing
if/when/why Unbind() is recommended. I raise six questions below.

I am using Python 2.7.2, wxPython 2.8.12.1, win32, (wxMSW, Unicode,
wx-assertions-on, SWIG-1.3.29)

Example A: thisPanel.Bind(wx.EVT_BUTTON, thisPanel.onButton,
                          source=thisPanel.button)
My understanding from Robin Dunns' notes in this forum: when thisPanel.Destroy
is invoked, the dynamic event handler table (of thisPanel) is destroyed after
pending events are processed.

Q1. thisPanel.Unbind(wx.EVT_BUTTON) does not need to be invoked
    before invoking thisPanel.Destroy(), correct?

Example B: thisFrame.Bind(wx.EVT_BUTTON, thisPanel.onButton,
                          source=thisPanel.button)
Here thisFrame is the parent of thisPanel, and it will not be closed/destroyed.

Q2. Should the UnBind() below be invoked before thisPanel.Destroy()?

    thisFrame.Unbind(wx.EVT_BUTTON, handler=thisPanel.onButton,
                          source=thisPanel.button)

Q3. What problems (e.g. memory growth) might result if
    this Unbind() is not done?

Example C: anotherFrame.Bind(wx.EVT_BUTTON, thisPanel.onButton,
                            source=anotherFrame.button)
Here anotherFrame is outside the containment hierarchy of thisPanel's parents
and children, and it will not be closed/destroyed.

Q4. I presume this should be treated like Example B,
    e.g. anotherFrame.Unbind(… handler=thisPanel.onButton) before
    invoking thisPanel.Destroy()? Are there different problems that
    might result if this is not done?

Currently panel methods are bound to events within their class __init__()
method. Instead of invoking thisPanel.Destroy() external to the class methods, I
propose to invoke thisPanel.Close(). Each panel would implement this:

    def __init__(self, ...):
        ...
        self.Bind(wx.EVT_CLOSE, self.OnClose)

    def OnClose(self, evt):
        """Unbind() any methods of this instance that are
        bound to event sources (menu items or windows) that
        are not children of this instance."""
        ...
        self.Destroy()

Q5. Would this work, and would it be considered good Python/wxPython style?

Curiously, Bind() and Unbind() are not included in the wxPython documentation
application titled "wxWidgets 2.8.12: A portable C++ and Python GUI toolkit",
though they can be found in their C++ form at
http://www.wxpython.org/docs/api/wx.EvtHandler-class.html. Alas, I do not know
C++, and am new to Python and wxPython.

Q6. Does this documentation difference imply that use of these
    methods is discouraged or deprecated?

Thank you in advance for your educational efforts on my behalf.

Another approach that you may wish to consider is to have one pane with
the maximum number of buttons on it, a page switch mechanism that
actually sets up a dictionary of button labels and methods and then
relabels and sets the buttons to visible or not, possibly based on the
length of the label, i.e.
for index in range(0, len(buttons)):
    button = buttons[index]
    (label, method) = LablesAndMethods[index]
    button.Show(len(label)>0)
    button.SetLabel(label)
    button.CurrentMethod = method
and have all the buttons bound to a single event handler that gets the
event object and calls its Method member, if any. The last line above
relies on the idea that python objects can have additional information
associated with them much more simply than C++ ones. Your limitation on
the number of controls is then set by the limit to the size of python
arrays, (very large), and even then the button/method tables could be
loaded from files on page switch freeing up a large amount of memory.
You could even have the methods as chunks of python within the same
files, (even if your application is compiled to an exe it still contains
python and the libraries it was bound with and can execute python loaded
from external files).

Gadget/Steve

···

On 02/03/2012 8:42 PM, Edward Perry wrote:

When is wx.EvtHandler.Unbind() recommended/required?

I am attempting maintenence of an application where users interact with hundreds
of controls per virtual page (implemented as a wx.Panel), and with scores of
such pages. Apparently some users must run other resource-intensive applications
concurrently, reportedly hitting the platform-specific (Windows XP) limit of 64k
native window objects. Reconfiguration of user kernels is not an acceptable
workaround.

I propose changing the application to instantiate panels only when they are
viewed, and then wx.Window.Destroy() them - instead of wx.Window.Hide() them -
when they are not in the users' view. But I cannot find an overview describing
if/when/why Unbind() is recommended. I raise six questions below.

I am using Python 2.7.2, wxPython 2.8.12.1, win32, (wxMSW, Unicode,
wx-assertions-on, SWIG-1.3.29)

Example A: thisPanel.Bind(wx.EVT_BUTTON, thisPanel.onButton,
                          source=thisPanel.button)
My understanding from Robin Dunns' notes in this forum: when thisPanel.Destroy
is invoked, the dynamic event handler table (of thisPanel) is destroyed after
pending events are processed.

Q1. thisPanel.Unbind(wx.EVT_BUTTON) does not need to be invoked
    before invoking thisPanel.Destroy(), correct?

Example B: thisFrame.Bind(wx.EVT_BUTTON, thisPanel.onButton,
                          source=thisPanel.button)
Here thisFrame is the parent of thisPanel, and it will not be closed/destroyed.

Q2. Should the UnBind() below be invoked before thisPanel.Destroy()?

    thisFrame.Unbind(wx.EVT_BUTTON, handler=thisPanel.onButton,
                          source=thisPanel.button)

Q3. What problems (e.g. memory growth) might result if
    this Unbind() is not done?

Example C: anotherFrame.Bind(wx.EVT_BUTTON, thisPanel.onButton,
                            source=anotherFrame.button)
Here anotherFrame is outside the containment hierarchy of thisPanel's parents
and children, and it will not be closed/destroyed.

Q4. I presume this should be treated like Example B,
    e.g. anotherFrame.Unbind(� handler=thisPanel.onButton) before
    invoking thisPanel.Destroy()? Are there different problems that
    might result if this is not done?

Currently panel methods are bound to events within their class __init__()
method. Instead of invoking thisPanel.Destroy() external to the class methods, I
propose to invoke thisPanel.Close(). Each panel would implement this:

    def __init__(self, ...):
        ...
        self.Bind(wx.EVT_CLOSE, self.OnClose)

    def OnClose(self, evt):
        """Unbind() any methods of this instance that are
        bound to event sources (menu items or windows) that
        are not children of this instance."""
        ...
        self.Destroy()

Q5. Would this work, and would it be considered good Python/wxPython style?

Curiously, Bind() and Unbind() are not included in the wxPython documentation
application titled "wxWidgets 2.8.12: A portable C++ and Python GUI toolkit",
though they can be found in their C++ form at
wxPython API Documentation — wxPython Phoenix 4.2.2 documentation. Alas, I do not know
C++, and am new to Python and wxPython.

Q6. Does this documentation difference imply that use of these
    methods is discouraged or deprecated?

Thank you in advance for your educational efforts on my behalf.

When is wx.EvtHandler.Unbind() recommended/required?

I am attempting maintenence of an application where users interact with hundreds
of controls per virtual page (implemented as a wx.Panel), and with scores of
such pages. Apparently some users must run other resource-intensive applications
concurrently, reportedly hitting the platform-specific (Windows XP) limit of 64k
native window objects. Reconfiguration of user kernels is not an acceptable
workaround.

I propose changing the application to instantiate panels only when they are
viewed, and then wx.Window.Destroy() them - instead of wx.Window.Hide() them -
when they are not in the users' view. But I cannot find an overview describing
if/when/why Unbind() is recommended. I raise six questions below.

I am using Python 2.7.2, wxPython 2.8.12.1, win32, (wxMSW, Unicode,
wx-assertions-on, SWIG-1.3.29)

Example A: thisPanel.Bind(wx.EVT_BUTTON, thisPanel.onButton,
                           source=thisPanel.button)
My understanding from Robin Dunns' notes in this forum: when thisPanel.Destroy
is invoked, the dynamic event handler table (of thisPanel) is destroyed after
pending events are processed.

Almost. Only top-level windows have the "after pending events" part of that built-in. If it's possible that you may be destroying the panel while there are still events pending (that you have bound event handlers for) then you may need to take some care about how you Destroy it. Using wx.CallAfter(thisPanel.Destroy) should be sufficient.

Q1. thisPanel.Unbind(wx.EVT_BUTTON) does not need to be invoked
     before invoking thisPanel.Destroy(), correct?

Correct.

Example B: thisFrame.Bind(wx.EVT_BUTTON, thisPanel.onButton,
                           source=thisPanel.button)
Here thisFrame is the parent of thisPanel, and it will not be closed/destroyed.

Q2. Should the UnBind() below be invoked before thisPanel.Destroy()?

     thisFrame.Unbind(wx.EVT_BUTTON, handler=thisPanel.onButton,
                           source=thisPanel.button)

It depends. If the button will have the same ID when the panel is recreated later then there is no real need to Unbind it and Bind it again when the new instance is created.

However, since the handler you are calling is also a member of the panel then it is poor OOP form to make the binding at the frame level. It is fully part of the functionality of your panel class so the binding should be encapsulated there too.

Q3. What problems (e.g. memory growth) might result if
     this Unbind() is not done?

Memory growth. Each binding adds an entry in the frame's dynamic event table. Another possible problem is if the same ID is used by a different button, then you could end up with the wrong handler function being called.

Example C: anotherFrame.Bind(wx.EVT_BUTTON, thisPanel.onButton,
                             source=anotherFrame.button)
Here anotherFrame is outside the containment hierarchy of thisPanel's parents
and children, and it will not be closed/destroyed.

Q4. I presume this should be treated like Example B,
     e.g. anotherFrame.Unbind(� handler=thisPanel.onButton) before
     invoking thisPanel.Destroy()? Are there different problems that
     might result if this is not done?

It wont matter because this binding would never work anyway. The anotherFrame object will not see the events happening in a different containment hierarchy.

Currently panel methods are bound to events within their class __init__()
method. Instead of invoking thisPanel.Destroy() external to the class methods, I
propose to invoke thisPanel.Close(). Each panel would implement this:

     def __init__(self, ...):
         ...
         self.Bind(wx.EVT_CLOSE, self.OnClose)

     def OnClose(self, evt):
         """Unbind() any methods of this instance that are
         bound to event sources (menu items or windows) that
         are not children of this instance."""
         ...
         self.Destroy()

Q5. Would this work, and would it be considered good Python/wxPython style?

Yes it would work, but it is not necessary because the panel's dynamic event table will automatically be cleared when the panel is destroyed.

Curiously, Bind() and Unbind() are not included in the wxPython documentation
application titled "wxWidgets 2.8.12: A portable C++ and Python GUI toolkit",
though they can be found in their C++ form at
wxPython API Documentation — wxPython Phoenix 4.2.2 documentation.

Actually that is python-specific documentation at that link.

Alas, I do not know
C++, and am new to Python and wxPython.

http://wiki.wxpython.org/C%2B%2BGuideForwxPythoneers

Q6. Does this documentation difference imply that use of these
     methods is discouraged or deprecated?

No.

···

On 3/2/12 12:42 PM, Edward Perry wrote:

--
Robin Dunn
Software Craftsman