0x00 前述
在写PyQt的时候,会发现由于UI线程是独立的,因此我们不能够在其他逻辑线程中,直接去对UI进行操作。而PyQt给我们提供了一个Signal系统,让我们能够在多线程中,对UI进行安全的交互。
0x01 关于Events
一个GUI程序,大部分是基于事件驱动的。比如一个Button,它会有一个clicked事件在它被点击的时候触发。因此,我们就可以将逻辑处理函数connect到这个事件。
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.loginButton.clicked.connect(self.loginFunction)
    def loginFunction(self):
        pass
对于菜单栏里的菜单来说,他们的点击事件可以用triggered。
有时候,比如在一个ListWidget中,我们可能需要点击其中的一个item,并且需要获取这个item的数据。那么我们可以像下面这样,在触发事件的时候,传递我们触发的item。
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ListWidget_1.itemClicked.connect(self.function)
    def function(self, item):
        print(item.text())
有时候,我们需要在UI事件被触发的时候,额外传输数据给处理函数,在这是我们可以使用functools的partial来达到目的。
from functools import partial
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.Button_1.clicked.connect(partial(self.function, '123'))
    def function(self, data):
        print(data)
0x02 关于Signals
就像一开始所说,我们需要能够跨线程对UI进行更改,以及数据更新。这时候,我们就可以使用PyQt提供的Signal系统。
首先,我们需要创建一个pyqtSignal对象。(特别的,这个对象只能创建在类,而不能在实例里。并且,该类需要继承QtCore.Qobject)
class SignalTest(QtCore.QObject):
    updateDataSignal = QtCore.pyqtSignal(str)
    clickedButtonSignal = QtCore.pyqtSignal()
    def __init__(self, parent=None):
        super().__init__(parent)
        self.updateDataSignal.connect(self.printData)
        self.clickedButtonSignal.connect(self.buttonClicked)
    def printData(self, data):
        print(data)
    def buttonClicked(self):
        print('Button clicked.')
对于需要数据传递的Signal来说,可以直接在定义Signal的时候确定这个参数的类型,最后调用的时候直接传参即可。
调用一个Signal对象的时候,我们需要使用.emit()方法。
def fun():
    test = SignalTest()
    test.updateDataSignal.emit('1234')
    test.clickedButtonSignal.emit()