I'm currently migrating from wxPython 4.0.7 to wxPython 4.1.0. This changes the wx version from 3.0.x to 3.1.x.
Tl;dr:
Using a wx.ListCtrl
I sometimes get an error when I call event.Skip()
inside a wxEVT_SIZE
event handler. To Skip()
or not to Skip()
? (i.e. whats the default event handling for a wxEVT_SIZE
and do I need it?)
Long Version:
Using wx.ListCtrl
with event.Skip
inside the wxEVT_SIZE
handler produces an error in some of my forms (so I think there must be more to it). Now, I couldn't strip any of the occurrences down to have a minimal example, since the error kinda disappears randomly when I remove (seemingly) unrelated parts of the code. The error even disappears (sometimes) when I replace a long label with a shorter label. However, changing the Frame or Panel size doesn't change anything.
Here is, what I found out:
wx.ListCtrl
classwxEVT_COMMAND_LIST_ITEM_ACTIVATED
event, though an empty handler (with or without Skip()
) is enough to provoke the error.wxEVT_SIZE
eventevent.Skip()
in the wxEVT_SIZE
handlerIt seems like I can simply remove the event.Skip()
call inside the wxEVT_SIZE
handler and be done, but the relevant C++ Code seems like there is more going on.
Here is the error (note: the error does not crash the wxApp):
wx._core.wxAssertionError: C++ assertion "nNew != dynamicEvents.size()" failed at ..\..\src\common\event.cpp(1926) in wxEvtHandler::SearchDynamicEventTable():
The above exception was the direct cause of the following exception:
SystemError: <class 'wx._core.SizeEvent'> returned a result with an error set
The relevant C++ Code in the github repository can be found here: https://github.com/wxWidgets/wxWidgets/blob/e803408058186a7a9a61c456246f145abcaccd13/src/common/event.cpp#L1926
(Hint: This is the pinned wxWidget-version used in the wxPython 4.1.0 Release)
Any wx & C++ experts here, that may know what's going on?
I believe this assert can only be triggered if a handler calls Bind()
from its event handler, but skips the event, i.e. pretends that the event wasn't handled at all. In an ideal world, this should be possible and I think the assert is actually over-eager and needs to be relaxed, but for now, if you really need to do it like this, you must either:
Bind()
by using CallAfter()
.event.Skip()
.(note that the assert won't be always triggered in this case, you also need to delete a handler that was previously connected to the same object shortly before).
But generally speaking you should call Skip()
unless you have fully processed the event and don't want any other handlers, either those in the base class or the built-in ones, to run after yours. For wxEVT_SIZE
it means that you've performed the re-layout of the window yourself and don't want the base class to do anything. So the solution (1) is better because it can be used even if you do want the base class handler to run.