YieldFor. How to avoid wx.CallAfter events or custom events?

I have an application with a very dynamic UI (UI layout changes constantly with many new controls appearing and disappearing regularly).

I have a recurring, moderately long-duration (typically a few seconds) task that runs in the UI thread. (It must run in the UI thread as it is directly related to computations related to the UI changes I just mentioned).

I want to refresh my UI (layout/refresh, etc.) during the task so the application does not feel unresponsive for that long.

I have been using wx.Yield during the “long task” but it does not work perfectly because I want to avoid calling the handler for command events or for events generated by wx.CallAfter during the Yield since those depend on the “long task” having been completed.

I have tried to use YieldFor instead of Yield: wx.EventLoopBase.GetActive().YieldFor(wx.EVT_CATEGORY_UI) but my CallAfter methods are still being called during the yield.

Is there a way of specifying argumens in YieldFor to avoid CallAfter events?

If it turns out that I cannot avoid CallAfter events in YieldFor (which I fear because browsing https://github.com/wxWidgets/wxWidgets/blob/71a64c25faeeafa558162a47fd125919c7a4f752/include/wx/event.h suggests that CallAfter generates wxAsyncMethodCallEvent that are somehow special) then,

Is there a way of generating custom events in wxPython for which GetEventCategory does not return wx.EVT_CATEGORY_UI?

(If so I could replace my calls to wx.CallAfter with posting of these custom events that would be ignored during my YieldFor.)

Thank you in advance!

[By the way suggestions to refactor the application to avoid the long task or to break it into smaller chunks would not be helpful: The application is already multithreaded and the “long task” in the UI thread really is distilled to the minimum necessary with all non-UI work already moved to other threads]

I’m not 100% sure what you’re trying to achieve here but is there a reason you don’t declare a `wx.lib.newevent.NewEvent()´ then when you receive that, you can perform whatever specific actions are required.

I’m far from Dev, actually playing user, but what about GetEventCategory (self )

and filtering wxEVT_CATEGORY_THREAD :face_with_hand_over_mouth:

I personally don’t believe in messing around in the loop (especially from far away as python) and would stick to pursue other paths :sweat_smile:

Thank you.

I was able to solve my problem with virtually no coding by using wx.CallLater(0, my_callback) which posts an event of category wx.EVT_CATEGORY_TIMER, which gets skipped during yields triggered by wx.EventLoopBase.GetActive().YieldFor(wx.EVT_CATEGORY_UI) instead of wx.CallAfter(my_callback) which posts some internal event type that seems to always get processed during yields regardless of category filtering.

For the record, if I had not thought of this shortcut, next I was planning to investigate subclassing PyEvent to overwrite GetEventCategory to return wx.EVT_CATEGORY_THREAD instead of wx.EVT_CATEGORY_UI which PyEvent returns. And then creating those events by mimicking the implementation of wx.lib.newevent.NewEvent(), but returning an event of my class instead of PyEvent, and then posting one of those based on the feedback above.

I always wondered what this wx.CallLater could be good for :thinking:
it’s just a wrapper around wx.Timer and that generates a wx internal event: proper category etc (I assume when you talk of type you mean category)

there is no SetEventCategory and

wx.Event implementation returns wxEVT_CATEGORY_UI by default

so I can’t see how one could possibly filter non generic event categories via YieldFor :confounded:

I assume when you talk of type you mean category

Thank you. Indeed. I fixed it in the original post for clarity.

there is no SetEventCategory and
wx.Event implementation returns wxEVT_CATEGORY_UI by default
so I can’t see how one could possibly filter non generic event categories via YieldFor

I was planning to subclass PyEvent and implement GetEventCategory in my subclass so that it would return wxEVT_CATEGORY_THREAD. I have not tried it and I am not sure if the wxWidgets would have picked up my python method though.

I’m afraid subclassing PyEvent will be a dead end and these other EventCategories are wx internals, or at least not meant to be used from wxPython (there are threading classes in wx & this CATEGORY_THREAD will be used by those, I think)

but Python has much more to offer than threads and if your Gui is chocked then you should move everything else into a different process (look at a browser how many workers they pull up right from the start :rofl:) and do in the Gui process only Gui stuff

here is a nice example of a process pool executor