I'm using a custom QEventLoop instance in my code to simulate the QDialog.exec_()
function. That is, the ability to pause the python script at some point without freezing the GUI, and then, at some other point of time after the user manually interacts with the GUI, the program resumes its execution right after the QEventLoop.exec_()
call, by calling QEventLoop.quit()
. This is the exact behaviour of what a coroutine should look like.
To illustrate the example, here's a MRE of what I'm doing:
from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout, QRadioButton, QButtonGroup, QDialogButtonBox
from PySide2.QtCore import Qt, QTimer, QEventLoop
recursion = 5
def laterOn():
# Request settings from user:
dialog = SettingsForm()
# Simulate a coroutine.
# - Python interpreter is paused on this line.
# - Other widgets code will still execute as they are connected from Qt5 side.
dialog.exec_()
# After the eventloop quits, the python interpreter will execute from where
# it was paused:
# Using the dialog results:
if (dialog.result):
# We can use the user's response somehow. In this simple example, I'm just
# printing text on the console.
print('SELECTED OPTION WAS: ', dialog.group.checkedButton().text())
class SettingsForm(QWidget):
def __init__(self):
super().__init__()
vbox = QVBoxLayout()
self.setLayout(vbox)
self.eventLoop = QEventLoop()
self.result = False
a = QRadioButton('A option')
b = QRadioButton('B option')
c = QRadioButton('C option')
self.group = QButtonGroup()
self.group.addButton(a)
self.group.addButton(b)
self.group.addButton(c)
bbox = QDialogButtonBox()
bbox.addButton('Save', QDialogButtonBox.AcceptRole)
bbox.addButton('Cancel', QDialogButtonBox.RejectRole)
bbox.accepted.connect(self.accept)
bbox.rejected.connect(self.reject)
vbox.addWidget(a)
vbox.addWidget(b)
vbox.addWidget(c)
vbox.addWidget(bbox)
global recursion
recursion -= 1
if (recursion > 0):
QTimer.singleShot(0, laterOn)
def accept(self):
self.close()
self.eventLoop.quit()
self.result = True
def reject(self):
self.close()
self.eventLoop.quit()
self.result = False
def exec_(self):
self.setWindowModality(Qt.ApplicationModal)
self.show()
self.eventLoop.exec_()
###
app = QApplication()
# Initialize widgets, main interface, etc...
mwin = QWidget()
mwin.show()
QTimer.singleShot(0, laterOn)
app.exec_()
In this code, the recursion
variable control how many times different instances of QEventLoop are crated, and how many times its .exec_()
method is called, halting the python interpreter without freezing the other widgets.
It can be seen that the QEventLoop.exec_()
acts just like a yield
keyword from a python generator function. Is it correct to assume that yield
is used every time QEventLoop.exec()
is called? Or it's not something related to a coroutine at all, and another thing is happening at the background? (I don't know if there's a way to see the PySide2 source code, so that's why I'm asking.)