Search code examples
c++wxpythonwxwidgets

wxPython migration from 4.0.7 to 4.1.0: ListCtrl error while event handling


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:

  • The error is definitely linked to the usage of the wx.ListCtrl class
  • The error only occurs, when a function is bound to the wxEVT_COMMAND_LIST_ITEM_ACTIVATED event, though an empty handler (with or without Skip()) is enough to provoke the error.
  • The error only occurs when a function is bound to the wxEVT_SIZE event
  • The error only occurs when I call event.Skip() in the wxEVT_SIZE handler

It 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?


Solution

  • 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:

    1. Postpone calling Bind() by using CallAfter().
    2. Or avoid calling 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.