Skip to content

Instantly share code, notes, and snippets.

@JoeEveryman
Forked from smontanaro/tkasyncio.py
Last active March 23, 2023 04:30
Show Gist options
  • Save JoeEveryman/0da001d7d9207062ed2287fb5e4b64f9 to your computer and use it in GitHub Desktop.
Save JoeEveryman/0da001d7d9207062ed2287fb5e4b64f9 to your computer and use it in GitHub Desktop.
First attempt at asyncio integration of the Tk event loop
#!/usr/bin/env python3
"Testing the idea of providing an off-the-shelf Tk event loop for asyncio"
import asyncio
import random
from tkinter import Tk, Button
class AsyncTk(Tk):
"Basic Tk with an asyncio-compatible event loop"
def __init__(self):
super().__init__()
self.running = True
self.runners = [self.tk_loop()]
self.button_presses = []
async def tk_loop(self):
"asyncio 'compatible' tk event loop?"
# Is there a better way to trigger loop exit than using a state vrbl?
while self.running:
self.update()
await asyncio.sleep(0.05) # obviously, sleep time could be parameterized
if len(self.button_presses) > 0:
await self.button_presses.pop(0)
def stop(self):
self.running = False
async def run(self):
await asyncio.gather(*self.runners)
def add_button_coro(self, coro):
task = asyncio.create_task(coro)
self.button_presses.append(task)
class App(AsyncTk):
"User's app"
def __init__(self):
super().__init__()
self.create_interface()
self.runners.append(self.counter())
def create_interface(self):
b1 = Button(master=self, text='Random Float',
command=lambda: print("your wish, as they say...", random.random()))
b1.pack()
b2 = Button(master=self, text='Quit', command=self.stop)
b2.pack()
b3 = Button(master=self, text='Foo', command=lambda: self.add_button_coro(self.foo()))
b3.pack()
async def counter(self):
"sample async worker... (with apologies to Lawrence Welk)"
i = 1
while self.running:
print("and a", i)
await asyncio.sleep(1)
i += 1
async def foo(self):
print(f"IO task foo has started")
await asyncio.sleep(1)
print(f"IO task foo has finished")
async def main():
app = App()
await app.run()
if __name__ == '__main__':
asyncio.run(main())
@mantisbug
Copy link

@smontanaro & @JoeEveryman: I will start using this tkasyncio.py structure for my project. Not sure it will work, but solves trouble and fixes ugly programming I have messed with for a while trying to make BLE and asyncio run within my GUI. I have already thanked @smontanaro last year but I gave up then. I have to restart that project yet again and really need to make it work. So grateful you share your knowledge. Thanks.

@smontanaro
Copy link

Thanks for the feedback. I took @JoeEveryman's changes and created an actual repo. You might want to play with that:

https://github.com/smontanaro/tk-asyncio

If nothing else, it will be easier to open issues or PRs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment