diff options
Diffstat (limited to 'examples/async/minimal/minimal_asyncio.py')
| -rw-r--r-- | examples/async/minimal/minimal_asyncio.py | 59 |
1 files changed, 32 insertions, 27 deletions
diff --git a/examples/async/minimal/minimal_asyncio.py b/examples/async/minimal/minimal_asyncio.py index 337a2558d..497e388a1 100644 --- a/examples/async/minimal/minimal_asyncio.py +++ b/examples/async/minimal/minimal_asyncio.py @@ -5,18 +5,17 @@ from PySide6.QtCore import (Qt, QEvent, QObject, Signal, Slot) from PySide6.QtWidgets import (QApplication, QLabel, QMainWindow, QPushButton, QVBoxLayout, QWidget) import asyncio -import outcome import signal import sys -import traceback class MainWindow(QMainWindow): - def __init__(self, async_signal): - super().__init__() + start_signal = Signal() + done_signal = Signal() - self.async_signal = async_signal + def __init__(self): + super().__init__() widget = QWidget() self.setCentralWidget(widget) @@ -32,21 +31,20 @@ class MainWindow(QMainWindow): @Slot() def async_start(self): - self.async_signal.emit() + self.start_signal.emit() async def set_text(self): await asyncio.sleep(1) self.text.setText("What do you get if you multiply six by nine?") + self.done_signal.emit() class AsyncHelper(QObject): - trigger_signal = Signal() - class ReenterQtObject(QObject): """ This is a QObject to which an event will be posted, allowing - Trio to resume when the event is handled. event.fn() is the - next entry point of the Trio event loop. """ + asyncio to resume when the event is handled. event.fn() is + the next entry point of the asyncio event loop. """ def event(self, event): if event.type() == QEvent.User + 1: event.fn() @@ -55,22 +53,26 @@ class AsyncHelper(QObject): class ReenterQtEvent(QEvent): """ This is the QEvent that will be handled by the ReenterQtObject. - self.fn is the next entry point of the Trio event loop. """ + self.fn is the next entry point of the asyncio event loop. """ def __init__(self, fn): super().__init__(QEvent.Type(QEvent.User + 1)) self.fn = fn - def __init__(self, entry=None): + def __init__(self, worker, entry): super().__init__() self.reenter_qt = self.ReenterQtObject() self.entry = entry self.loop = asyncio.new_event_loop() + self.done = False - def set_entry(self, entry): - self.entry = entry + self.worker = worker + if hasattr(self.worker, "start_signal") and isinstance(self.worker.start_signal, Signal): + self.worker.start_signal.connect(self.on_worker_started) + if hasattr(self.worker, "done_signal") and isinstance(self.worker.done_signal, Signal): + self.worker.done_signal.connect(self.on_worker_done) @Slot() - def launch_guest_run(self): + def on_worker_started(self): """ To use asyncio and Qt together, one must run the asyncio event loop as a "guest" inside the Qt "host" event loop. """ if not self.entry: @@ -78,13 +80,23 @@ class AsyncHelper(QObject): asyncio.set_event_loop(self.loop) self.loop.create_task(self.entry()) self.loop.call_soon(self.next_guest_run_schedule) + self.done = False # Set this explicitly as we might want to restart the guest run. self.loop.run_forever() + @Slot() + def on_worker_done(self): + """ When all our current asyncio tasks are finished, we must end + the "guest run" lest we enter a quasi idle loop of switching + back and forth between the asyncio and Qt loops. We can + launch a new guest run by calling launch_guest_run() again. """ + self.done = True + def continue_loop(self): """ This function is called by an event posted to the Qt event - loop to restart the asyncio event loop. """ - self.loop.call_soon(self.next_guest_run_schedule) - self.loop.run_forever() + loop to continue the asyncio event loop. """ + if not self.done: + self.loop.call_soon(self.next_guest_run_schedule) + self.loop.run_forever() def next_guest_run_schedule(self): """ This function serves to pause and re-schedule the guest @@ -102,15 +114,8 @@ class AsyncHelper(QObject): if __name__ == "__main__": app = QApplication(sys.argv) - async_helper = AsyncHelper() - main_window = MainWindow(async_helper.trigger_signal) - async_helper.set_entry(main_window.set_text) - - # This establishes the entry point for the Trio guest run. It varies - # depending on how and when its event loop is to be triggered, e.g., - # at a specific moment like a button press (as here) or rather from - # the beginning. - async_helper.trigger_signal.connect(async_helper.launch_guest_run) + main_window = MainWindow() + async_helper = AsyncHelper(main_window, main_window.set_text) main_window.show() |
