Search code examples
pythondatagridwxpython

How to programmatically generate an event in wxPython


I have a wxPython gui and I want to programmatically generate an event.

I've tried a syntax like this:

e = wx.Event.__init__(grid, eventType=wx.EVT_LEFT_DOWN)

which results in:

TypeError: unbound method __init__() must be called with Event instance as first argument (got Grid instance instead)

or:

 e = wx.CommandEvent(commandType=wx.EVT_BUTTON)

TypeError: in method 'new_CommandEvent', expected argument 1 of type 'wxEventType'

So question is simply, what is the exact, literal syntax that I need to use to create an event object? Or, can someone point me to a good resource for making sense of events? I don't know if I'm just missing something simple in my understanding. I haven't been able to find a direct answer to this question yet online. I checked out this question: Generate a custom CommandEvent in wxPython , but I don't want to make a custom event.

Thanks in advance!


Solution

  • You would want to use wx.PostEvent

    To programatically generate an event:

    wx.PostEvent(self.GetEventHandler(), wx.PyCommandEvent(wx.EVT_BUTTON.typeId, self.GetId()))
    

    if you want to post a wx.EVT_BUTTON event. Making it a PyCommandEvent means it will propagate upwards; other event types don't propagate by default.

    The general form of wx.PostEvent(): http://www.wxpython.org/docs/api/wx-module.html#PostEvent

    Here's a small example code:

    import wx
    
    class MyFrame ( wx.Frame ):
    
        def __init__( self, parent ):
            wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Test", pos = wx.DefaultPosition, size = wx.Size( 200,200 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
    
            sizer_inside = wx.BoxSizer( wx.VERTICAL )
    
            # Adding a button and a textCtrl widget
            self.button = wx.Button( self, wx.ID_ANY, u"Click Me", wx.DefaultPosition, wx.DefaultSize, 0 )
            sizer_inside.Add( self.button, 0, wx.ALIGN_CENTER|wx.ALL, 5 )
            self.textCtrl = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_NO_VSCROLL )
            sizer_inside.Add( self.textCtrl, 0, wx.ALIGN_CENTER|wx.ALL, 5 )
    
            self.SetSizer( sizer_inside )
            self.Layout()
            self.Centre( wx.BOTH )
            self.Show()
    
            self.counter = 0
    
            # Binding Events
            self.Bind( wx.EVT_BUTTON, self.on_click )
            self.Bind( wx.EVT_CHOICE, self.test_dummy)
    
        #Event handlers
        def on_click( self, event ):
            self.counter += 1
            wx.PostEvent(self.GetEventHandler(), wx.PyCommandEvent(wx.EVT_CHOICE.typeId, self.GetId()))
    
        def test_dummy(self, event):
            self.counter += 1
            self.textCtrl.SetValue(str(self.counter))
    
    if __name__ == "__main__":
        app = wx.App(False)
        MyFrame(None)
        app.MainLoop()
    

    If you run this, notice that the textCtrl will display 2 after clicking the button. The first event handler manually fires the second event which is handled by test_dummy.