-
-
Save JoeEveryman/0da001d7d9207062ed2287fb5e4b64f9 to your computer and use it in GitHub Desktop.
First attempt at asyncio integration of the Tk event loop
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
#!/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()) |
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
@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.