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()
你看,所有GUI的机制终会导向某种Windows的设计思路(逃