Event Handling Order for Multiple Handlers of the Same Event

This forum can be used to talk about general design strategies, new ideas and questions in general related to wxWidgets. If you feel your questions doesn't fit anywhere, put it here.
Post Reply
Bejam1n
In need of some credit
In need of some credit
Posts: 2
Joined: Thu Aug 30, 2012 5:20 pm

Event Handling Order for Multiple Handlers of the Same Event

Post by Bejam1n »

I am a "relatively" experienced user with wxPython but have always had trouble with how wxPython deals with binding multiple event handlers to the same event (I know that that I am being general as of yet, hopefully my example below is more specific). This is not a question about "event propagation" as it usually referred to in the wxPython docs/FAQS/tutorials.

Here is the sample code (If it didn't come out right: I had trouble figuring out the code block system for the forum):

Code: Select all

import wx

class MainFrame(wx.Frame):
    def __init__(self, parent, ID, title):
       wx.Frame.__init__(self, parent, ID, title,
                      wx.DefaultPosition, wx.Size(200, 100))

       Panel = wx.Panel(self, -1)
       TopSizer = wx.BoxSizer(wx.VERTICAL)
       Panel.SetSizer(TopSizer)

       Text = wx.TextCtrl(Panel, -1, "Type text here")
       TopSizer.Add(Text, 1, wx.EXPAND)

       Text.Bind(wx.EVT_KEY_DOWN,self.OnKeyText)
       Text.Bind(wx.EVT_KEY_DOWN, self.OnKeyText2)


    def OnKeyText(self, event):
        print "OnKeyText"
        event.Skip()

    def OnKeyText2(self, event):
        print "OnKeyText2"
        event.Skip()

class MyApp(wx.App):
    def OnInit(self):
        Frame = MainFrame(None, -1, "Event Order Demo")
        Frame.Show(True)
        self.SetTopWindow(Frame)
        return True

if __name__ == '__main__':
    App = MyApp(0)
    App.MainLoop()
The function "OnKeyText2" gets executed first, so I figure the behavior for the "event stack" (Is there a proper terminology for this part of wxPython instead of "event stack"?) for this control is: Each new handler bound to the same event at the same level of propagation goes to the top of the stack (executed first) and not the bottom (executed second).

Even though I understand this, it has become a real pain in my application because I have subclasses of a class where the base class functions bind some events, then the subclasses bind their additional events afterwords.

I feel like the events get put into the "event stack" backwards (bind the event you want to have happen last first). Is there a way to have the events append to the "event stack" and not be inserted in the beginning?

If I am misunderstanding the event.Skip() command or am missing something, please let me know! :) Is there a better way to do what I am trying to do? I don't want to have the events strung together (For example: have OnKeyText(), once done, call OnKeyText2()) because in my app one of the event handlers is shared by all subclasses and the other is not.

If the answer is that "it just needs to be done in reverse order" then I will have to accept that and make the changes to my app.

If the answer is that I should use event propagation between the control and the panels to control the order of event handlers, I feel like I run into the same problem unless I keep the number of event handlers to one for each propagation level.

Thanks in advance! Benjamin
Bejam1n
In need of some credit
In need of some credit
Posts: 2
Joined: Thu Aug 30, 2012 5:20 pm

Re: Event Handling Order for Multiple Handlers of the Same E

Post by Bejam1n »

I found wx.EvtHandler.SetNextHandler in the _core.py module. Is that the answer?
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Event Handling Order for Multiple Handlers of the Same E

Post by doublemax »

I found wx.EvtHandler.SetNextHandler in the _core.py module. Is that the answer?
I don't think so.

I think it's a deliberate design decision that later added event handlers are executed first. It *feels* the right thing to do for me, although i can't argue why :)

I would approach your problem this way: Let only the base class connect the event. The event handler just calls a virtual method like DoHandleEvent(...). In the subclasses you override that method when needed and let virtual functions do their magic.

(That's for C++. As Python is supposed to be more modern than C++, i assume it works the same way - or better - there ;) )
Use the source, Luke!
moraleda
In need of some credit
In need of some credit
Posts: 2
Joined: Mon Oct 25, 2021 8:35 pm

Re: Event Handling Order for Multiple Handlers of the Same Event

Post by moraleda »

I just encountered this exact issue. I was able to make the event handler in the base class called before the event handler in the derived class by delaying the Bind call in the constructor of the base class until after the Bind call in the constructor of the derived class. I achieved this reversal by using wx.CallAfter for the Bind call in the base class but not in the derived class.

In the example given in the original question, the first binding would be delayed and made after the second binding by modifying the line that performs the first binding as follows:

Code: Select all

wx.CallAfter(Text.Bind, wx.EVT_KEY_DOWN, self.OnKeyText)
Note: This work around performs exactly as intended in this case, with a base class and a derived class, but I think it would not produce the intended order if there were more than two levels of inheritance, each with its own event handler.
Post Reply