Last active
March 2, 2019 01:04
-
-
Save abulka/3c9230dc2a85ab5941a2f81ef2f29ee2 to your computer and use it in GitHub Desktop.
Complete wxasync wxPython app which avoids the turtle problem
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import wx | |
from wxasync import AsyncBind, WxAsyncApp, StartCoroutine | |
import asyncio | |
from asyncio.events import get_event_loop | |
import time | |
import wx.lib.newevent | |
SomeNewEvent, EVT_SOME_NEW_EVENT = wx.lib.newevent.NewEvent() | |
SomeNewEventAsync, EVT_SOME_NEW_EVENT_ASYNC = wx.lib.newevent.NewEvent() | |
class TestFrame(wx.Frame): | |
def __init__(self, parent=None): | |
super(TestFrame, self).__init__(parent) | |
vbox = wx.BoxSizer(wx.VERTICAL) | |
button1 = wx.Button(self, label="AsyncBind (original wxasync example)") | |
button2 = wx.Button(self, label="Start/stop clock via StartCoroutine()") | |
button3 = wx.Button(self, label="Emit Custom Event (sync)") | |
button4 = wx.Button(self, label="Emit Custom Event (async)") | |
button5 = wx.Button(self, label="Show Frame") | |
self.edit = wx.StaticText(self, style=wx.ALIGN_CENTRE_HORIZONTAL|wx.ST_NO_AUTORESIZE) | |
self.edit_timer = wx.StaticText(self, style=wx.ALIGN_CENTRE_HORIZONTAL|wx.ST_NO_AUTORESIZE) | |
vbox.Add(button1, 2, wx.EXPAND|wx.ALL) | |
vbox.Add(button2, 2, wx.EXPAND|wx.ALL) | |
vbox.Add(button3, 2, wx.EXPAND|wx.ALL) | |
vbox.Add(button4, 2, wx.EXPAND|wx.ALL) | |
vbox.Add(button5, 2, wx.EXPAND|wx.ALL) | |
vbox.AddStretchSpacer(1) | |
vbox.Add(self.edit, 1, wx.EXPAND|wx.ALL) | |
vbox.Add(self.edit_timer, 1, wx.EXPAND|wx.ALL) | |
self.SetSizer(vbox) | |
self.Layout() | |
self.clock_on = False | |
"""Binding of button event to async method""" | |
AsyncBind(wx.EVT_BUTTON, self.async_callback, button1) | |
""" | |
Regular method calls StartCoroutine() | |
No need for async/await syntax except on the final async method! Turtle avoidance success | |
because no need for async/await syntax turtles all the way up the calling chain. | |
""" | |
self.Bind(wx.EVT_BUTTON, self.regular_func_starts_coroutine, button2) | |
""" | |
Synchronous method broadcast a custom event - works ok | |
But this is the synchronous version. Its the async version we want to get working. | |
""" | |
self.Bind(wx.EVT_BUTTON, self.regular_func_raises_custom_event, button3) | |
self.Bind(EVT_SOME_NEW_EVENT, self.callback) # bind custom event to synchronous handler - works OK | |
""" | |
Bind button to run regular synchronous code, which raises an event | |
Bind custom event to asynchronous handler | |
""" | |
self.Bind(wx.EVT_BUTTON, self.regular_func_raises_custom_async_event, button4) | |
AsyncBind(EVT_SOME_NEW_EVENT_ASYNC, self.async_callback, self) # don't specify id | |
"""Show popup frame""" | |
self.Bind(wx.EVT_BUTTON, self.on_show_frame, button5) | |
def regular_func_raises_custom_event(self, event): | |
print("trigger demo via custom event") | |
# Create and post the event | |
evt = SomeNewEvent(attr1="hello", attr2=654) | |
wx.PostEvent(self, evt) | |
def regular_func_raises_custom_async_event(self, event): | |
print("trigger async demo via custom event") | |
# Create and post the event | |
evt = SomeNewEventAsync(attr1="hello", attr2=654) | |
wx.PostEvent(self, evt) | |
def regular_func_starts_coroutine(self, event): | |
self.clock_on = not self.clock_on | |
if self.clock_on: | |
print(f"triggering an async call via StartCoroutine()") | |
StartCoroutine(self.update_clock, self) | |
else: | |
print("clock flag off, coroutine will stop looping, drop through and complete") | |
def on_show_frame(self, event): # not used | |
"""manually build a frame with inner html window, no sizer involved""" | |
class MyPopupFrame(wx.Frame): | |
def __init__(self, parent, title): | |
super(MyPopupFrame, self).__init__(parent, title=title) | |
frm = MyPopupFrame(parent=self, title="Simple Popup Frame") | |
frm.Show() | |
def callback(self, event): | |
self.edit.SetLabel("Button clicked (synchronous)") | |
wx.SafeYield() | |
time.sleep(1) | |
self.edit.SetLabel("Working (synchronous)") | |
wx.SafeYield() | |
time.sleep(1) | |
self.edit.SetLabel("Completed (synchronous)") | |
wx.SafeYield() | |
time.sleep(1) | |
self.edit.SetLabel("") | |
async def async_callback(self, event): | |
self.edit.SetLabel("Button clicked") | |
await asyncio.sleep(1) | |
self.edit.SetLabel("Working") | |
await asyncio.sleep(1) | |
self.edit.SetLabel("Completed") | |
await asyncio.sleep(1) | |
self.edit.SetLabel("") | |
async def update_clock(self): | |
while self.clock_on: | |
self.edit_timer.SetLabel(time.strftime('%H:%M:%S')) | |
await asyncio.sleep(0.5) | |
self.edit_timer.SetLabel("") | |
app = WxAsyncApp() | |
frame = TestFrame() | |
frame.Show() | |
app.SetTopWindow(frame) | |
loop = get_event_loop() | |
loop.run_until_complete(app.MainLoop()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment