如何将函数连接到主线程之外的PyQt信号



我正在创建一个PyQt应用程序,我希望在其中有一个后台线程连接一些事件处理程序,然后永远循环,直到主窗口关闭。我遇到的问题是,我连接的事件处理程序只有在MainWindow类中定义的函数时才能工作。我在下面创建了一个最小的repo:

import threading
from PyQt5.QtWidgets import QApplication, QDialog, QPushButton, QVBoxLayout

class MainWindow(QDialog):
def __init__(self):
super(MainWindow, self).__init__()
self.button1 = QPushButton("Click Me", self)
self.button2 = QPushButton("Me Too!", self)
layout = QVBoxLayout()
layout.addWidget(self.button1)
layout.addWidget(self.button2)
self.setLayout(layout)
def test(self):
print("test inside class")

def test2():
print("test outside class")

def main(window):
window.button1.clicked.connect(window.test)
window.button2.clicked.connect(test2)
# Loop that runs in thread...

app = QApplication([])
window = MainWindow()
window.show()
threading.Thread(target=main, args=[window]).start()
app.exec_()

当我运行这段代码时,第一个按钮会按预期向控制台打印一条消息,但第二个按钮在单击时什么也不做。如果我在主线程中运行main(window)函数,那么两个按钮都可以工作。我知道在我的小示例程序中,这将是显而易见的解决方案,但由于解释起来很复杂的原因,我需要能够从应用程序的后台线程连接事件处理程序。为什么连接像test2()这样在MainWindow类之外定义的函数在主线程之外进行时不起作用?

我仍在找出问题的原因,但解决方案是指示连接的类型,在本例中为Qt::DirectConnection,它将使函数test2在发出信号的对象的同一线程上运行(发出信号的物体是主线程中的按钮(。

import threading
from PyQt5 import QtCore, QtWidgets
class MainWindow(QtWidgets.QDialog):
def __init__(self):
super(MainWindow, self).__init__()
self.button1 = QtWidgets.QPushButton("Click Me")
self.button2 = QtWidgets.QPushButton("Me Too!")
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.button1)
layout.addWidget(self.button2)
@QtCore.pyqtSlot()
def test(self):
print("test inside class")
def test2():
print("test outside class")
def main(window):
window.button1.clicked.connect(window.test)
window.button2.clicked.connect(test2, QtCore.Qt.DirectConnection)
while True:
QtCore.QThread.sleep(1)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
threading.Thread(target=main, args=(window,), daemon=True).start()
sys.exit(app.exec_())

最新更新