PyQt5: неожиданное поведение processEvents (QtCore.QEventL oop .WaitForMoreEvents) в многопоточной среде - PullRequest
0 голосов
/ 20 января 2020

После обновления с PyQt 5.13.2 до PyQt 5.14.0 я наблюдал странное изменение поведения app.processEvents(QtCore.QEventLoop.WaitForMoreEvents) в многопоточной среде.

Насколько я понимаю, если этот метод выполняется когда очередь событий пуста, она должна блокироваться до появления нового события и обрабатывать его. Однако иногда кажется, что метод помечает событие как «обработанное» без фактической его обработки.

Вот соответствующий код:

from PyQt5 import QtCore, QtWidgets

import time

class Thread(QtCore.QThread):

    def __init__(self):
        QtCore.QThread.__init__(self)
        self.moveToThread(self)
        self.var=False
        self.set_var_signal.connect(self.set_variable,type=QtCore.Qt.QueuedConnection)

    # setup simple signal and slot
    set_var_signal=QtCore.pyqtSignal()
    @QtCore.pyqtSlot()
    def set_variable(self):
        assert QtCore.QThread.currentThread() is self  # make sure that it runs in the correct thread
        print("Set variable")
        self.var=True

    def run(self):
        assert QtCore.QThread.currentThread() is self  # make sure that it runs in the correct thread
        time.sleep(1.)
        app.processEvents()  # "clean up" all the sent events
        print("First check:",self.var)
        app.processEvents(QtCore.QEventLoop.WaitForMoreEvents)  # here we wait for the signal event
        print("Second check:",self.var)
        app.processEvents()  # "post-processing"; in principle, it should do nothing
        print("Third check:",self.var)


app=QtWidgets.QApplication([])
th=Thread()
th.start()
time.sleep(2.) # wait until the thread is up and running
th.set_var_signal.emit()
time.sleep(3.) # wait to display the messages

Короче говоря, он создает отдельный поток с одна переменная и сигнал, который изменяет значение этой переменной. Этот поток ожидает, пока этот сигнал не будет получен и обработан, а затем печатает значение переменной. Я ожидаю, что результат будет

First check: False
Set variable
Second check: True
Third check: True

То есть изначально (после первого вызова processEvents) переменная по-прежнему False. После второго (блокирующего) вызова переменная устанавливается, и ее значение сообщается как True. После третьего звонка ничего не меняется. Действительно, это то, что я наблюдаю с PyQt 5.13.2.

Однако после обновления до PyQt 5.14.0 результат меняется на

First check: False
Second check: False
Set variable
Third check: True

В этом случае, даже если второй вызов на processEvents возвращает (что должно произойти только после обработки сигнала), состояние переменной все еще остается неизменным. Только после следующего вызова подключенный слот фактически выполняется. Более того, если в третьем («постобработка») вызове я также добавлю флаг QtCore.QEventLoop.WaitForMoreEvents, результат превратится в

First check: False
Second check: False
Set variable

Т.е. этот последний вызов processEvents заблокирован навсегда, даже если слот явно выполняется внутри этого вызова.

Это поведение меня сильно озадачивает, тем более что я не смог найти ничего релевантного в списке изменений между Qt 5.13 и 5.14 ( Новые функции в Qt 5.14 и Qt 5.14.0 Файлы изменений ). Что-то я не понимаю в связи между сигналами и событиями в PyQt? Я всегда предполагал, что сигналы подаются поверх событий, т. Е. Обработка события представляет собой выполнение соответствующего слота. Разве это не так?

...