Skip to content

Instantly share code, notes, and snippets.

@ericfrederich
Created March 10, 2016 05:13
Show Gist options
  • Save ericfrederich/1ec11a8f933ed6289b95 to your computer and use it in GitHub Desktop.
Save ericfrederich/1ec11a8f933ed6289b95 to your computer and use it in GitHub Desktop.
Example of using an asyncio coroutine as a Qt slot
import math
import sys
import asyncio
from functools import partial
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QGridLayout, QProgressBar
from quamash import QEventLoop
class MyWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
layout = QGridLayout()
self.pairs = []
for i in range(10):
b = QPushButton('Countdown: &%d' % i, clicked=partial(self.on_click, i))
p = QProgressBar(visible=False)
layout.addWidget(b, i, 0)
layout.addWidget(p, i, 1)
self.pairs.append((b, p))
self.setLayout(layout)
def on_click(self, i):
b, p = self.pairs[i]
asyncio.ensure_future(self.do_countdown(b, p, i))
@staticmethod
async def do_countdown(b, p, n):
b.setEnabled(False)
p.setVisible(True)
i = n * 100
p.setMaximum(i)
while i >= 0:
await asyncio.sleep(0.01)
p.setValue(i)
b.setText('Countdown: %d' % math.ceil(i/100))
i -= 1
b.setText('Countdown: &%d' % n)
b.setEnabled(True)
p.setVisible(False)
def main():
app = QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop) # NEW must set the event loop
w = MyWidget()
w.show()
with loop:
loop.run_forever()
if __name__ == '__main__':
main()
@danieljfarrell
Copy link

danieljfarrell commented Mar 20, 2019

Thanks for this, it was really useful!

Added a decorator on my fork which allows you to connect coroutines "directly" to the Qt signals.

@slot_coroutine
async def on_button_clicked(self, button_index):
    # handle button click

and you would connect to the button like this,

button.clicked.connect(partial(self.on_click_coroutine, i))

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