-
Notifications
You must be signed in to change notification settings - Fork 10
Open
Description
def CreatePopupMenu(self, event=None):
menu = wx.Menu()
item_open = menu.Append(wx.ID_ANY, "Open App")
item_about = menu.Append(wx.ID_ANY, "About…")
item_settings = menu.Append(wx.ID_SETUP, "Settings…")
item_exit = menu.Append(wx.ID_EXIT, "Exit")
self.Bind(wx.EVT_MENU, self.on_open_app, item_open)
self.Bind(wx.EVT_MENU, self.on_about, item_about)
AsyncBind(wx.EVT_MENU, self.on_open_settings, item_settings, self)
self.Bind(wx.EVT_MENU, self.on_exit, item_exit)
# parent will do self.PopupMenu(menu)
return menu
async def on_open_settings(self, parent=None, event=None):
print("Would you like to open the settings dialog?")
dialog = SettingsDialog(self.parent)
# dialog.ShowModal()
await AsyncShowDialog(dialog)Traceback (most recent call last):
File "/Users/user/Documents/programming/Python/FaceIt/root/ui.py", line 34, in CreatePopupMenu
AsyncBind(wx.EVT_MENU, self.on_open_settings, item_settings, self)
File "/Users/user/Documents/programming/Python/FaceIt/.venv/lib/python3.12/site-packages/wxasync.py", line 109, in AsyncBind
app.AsyncBind(event, async_callback, object, source=source, id=id, id2=id2)
File "/Users/user/Documents/programming/Python/FaceIt/.venv/lib/python3.12/site-packages/wxasync.py", line 57, in AsyncBind
raise Exception("object must be a wx.Window")
Exception: object must be a wx.Window
A code comment there says:
We restrict the object to wx.Windows to be able to cancel the coroutines on EVT_WINDOW_DESTROY, even if wx.Bind works with any wx.EvtHandler
Lines 52 to 64 in 3ecfe36
def AsyncBind(self, event_binder, async_callback, object, source=None, id=wx.ID_ANY, id2=wx.ID_ANY): """Bind a coroutine to a wx Event. Note that when wx object is destroyed, any coroutine still running will be cancelled automatically. """ # We restrict the object to wx.Windows to be able to cancel the coroutines on EVT_WINDOW_DESTROY, even if wx.Bind works with any wx.EvtHandler if not isinstance(object, wx.Window): raise Exception("object must be a wx.Window") if not iscoroutinefunction(async_callback): raise Exception("async_callback is not a coroutine function") if object not in self.BoundObjects: self.BoundObjects[object] = defaultdict(list) object.Bind(wx.EVT_WINDOW_DESTROY, lambda event: self.OnDestroy(event, object), object) self.BoundObjects[object][event_binder.typeId].append(async_callback) object.Bind(event_binder, lambda event: StartCoroutine(async_callback(event.Clone()), object), source=source, id=id, id2=id2)
Possible solution
From my understanding the following could allow a user to use this for tray menus:
- def AsyncBind(self, event_binder, async_callback, object, source=None, id=wx.ID_ANY, id2=wx.ID_ANY):
+ def AsyncBind(self, event_binder, async_callback, object, source=None, id=wx.ID_ANY, id2=wx.ID_ANY, parent_window: wx.Window | None = None):
"""Bind a coroutine to a wx Event. Note that when wx object is destroyed, any coroutine still running will be cancelled automatically.
"""
# We restrict the object to wx.Windows to be able to cancel the coroutines on EVT_WINDOW_DESTROY, even if wx.Bind works with any wx.EvtHandler
- if not isinstance(object, wx.Window):
+ if not isinstance(object, wx.Window) and (not parent_window or not isinstance(parent_window, wx.Window)):
- raise Exception("object must be a wx.Window")
+ raise Exception("object must be a wx.Window, or you need to provide parent_window")
if not iscoroutinefunction(async_callback):
raise Exception("async_callback is not a coroutine function")
+ bind_on = object if isinstance(object, wx.Window) else parent_window
if object not in self.BoundObjects:
self.BoundObjects[object] = defaultdict(list)
- object.Bind(wx.EVT_WINDOW_DESTROY, lambda event: self.OnDestroy(event, object), object)
+ bind_on.Bind(wx.EVT_WINDOW_DESTROY, lambda event: self.OnDestroy(event, bind_on), bind_on)
self.BoundObjects[object][event_binder.typeId].append(async_callback)
- object.Bind(event_binder, lambda event: StartCoroutine(async_callback(event.Clone()), object), source=source, id=id, id2=id2)
+ bind_on.Bind(event_binder, lambda event: StartCoroutine(async_callback(event.Clone()), object), source=source, id=id, id2=id2)
For my code above, I'd do
Metadata
Metadata
Assignees
Labels
No labels