wx.PyEvent - losing my mind?

I am implementing a threaded worker thread to work with my UI, and to communicate status back I’m using wx.PyEvent. However, I am having difficulties setting properties to the event.

Brief snippet:

EVT_BLIZZ_RESULT_ID = wx.NewId()


class BlizzEvent(wx.PyEvent):
    def __init__(self, eventData):
        wx.PyEvent.__init__(self, id=EVT_BLIZZ_RESULT_ID)
        self.SetEventType(EVT_BLIZZ_RESULT_ID)
        self.data = eventData
        print()

However, if I set a breakpoint at print(), what I see is: eventData is populated as expected, but self.data does NOT exist. What am I missing? Did wx.PyEvent change? I’m sure I’m just missing something on setting properties.

wx.PostEvent() does post this event to the UI frame, but minus self.data.

There’s actually a bit of magic (__setattr__ and etc.) going on there to help ensure that any Python attributes set in the event object are safe when the event is going through the wxWidgets event system. The attributes are set in a different dictionary (one owned by the C++ code) instead of the normal __dict__ . It’s possible that the the debugger is just looking in __dict__ for any attributes to display, but there isn’t anything there. You can get a look at the custom dictionary using the _getAttrDict method.

>>> my_evt_type = wx.NewEventType()
>>> 
>>> class MyEvent(wx.PyEvent):
...     def __init__(self, evtData):
...         wx.PyEvent.__init__(self)
...         self.SetEventType(my_evt_type)
...         self.data = evtData
...         
>>> 
>>> evt = MyEvent(25)
>>> 
>>> evt.data
25
>>> 

See: https://docs.wxpython.org/MigrationGuide.html#wx-pyevent-and-wx-pycommandevent

Also, notice the use of wx.NewEventType above instead of wx.NewId. Event types and IDs are slightly different things in wxWidgets.

There is a module in the library called newevent.py that contains some factory functions that can generate an event class and binder for you with just a single line of code. It makes creating custom events very easy. For example:

>>> import wx.lib.newevent as ne
>>> MooEvent, EVT_MOO = ne.NewEvent()
>>> 
>>> evt = MooEvent(data=dict(a=1, b=2, c=3))
>>> 
>>> evt.data
{'a': 1, 'b': 2, 'c': 3}
>>> 
1 Like

Robin,

I see now. The code I was leveraging was several years old, which explains why some elements appeared dated. I’ve updated my code to take your suggestions in.

So, stepping through this with the debugger, I was still not seeing the data embedded in the event instance either at creation time OR when the event handler was triggered. But I followed your advice and just assumed it would be there, and it was! “Magic” indeed. :slight_smile:

Thanks as always for your advice, helpful as always :wink:

I’ve just implemented it the way u show in the sample code.
It seems 2 work completely fine 4 me. data gets passed through.

What i was confused about, tho is why I couldn’t call

super().__init__(self)
self.eventData = xxx

custom data setting gave me the error of 'not having superclass constructor, i.e. __init__ called'.
y do i have 2 call it like

wx.PyEvent.__init__(self)

try super().__init__()