信号与槽
**信号(Signal)与 槽(Slot)**是Qt中对象之间的通信方式,可以用一个简单的栗子说明:当我们想要开灯时,按下开关发出指令,这就是信号;而灯泡接收到电流变化,发出光亮,这就是响应(槽)。
我们也可以换个称呼方式:
所有继承自QObject的类,都可以包含信号和槽。当对象的状态发生改变时,就会发出信号。当然,他并不关心是否有人接收到这个信号。
槽函数就是用来接收对象的一个方法或是接口,就跟信号发出去并不知道有没有槽接收一样,槽也不知道有没有信号来调动他,他只是个固有属性。
信号和槽之间的关系是开放多元的,你可以看见一个信号连接到好几个槽,也可以见到一个槽上有好几个信号。更诡异的是,甚至可以将一个信号插到另一个信号上。
Qt小组件有许多预定义的信号和槽,例如QAbstractButton有一个Clicked()的信号,QLineEdit有一个clear()的槽。一般通过信号的connect()方法,将信号与槽联系起来。例如:
1 2 3 button=QToolButton() line_edit=QLineEdit() button.clicked.connect(line_edit.clear)
connect()将会翻译一个QMetaObject对象,该对象可以与disconnect()方法使用,以断开连接。
当然,除了预设的函数外,信号也可以连接到自由函数:
1 2 3 4 5 6 7 8 9 10 11 import sysfrom PySide6.QtWidgets import QApplication,QPushButtondef function (): print ("The 'function' has been called" ) app=QApplication() button=QPushButton("Call function" ) button.clicked.connect(function) button.show() sys.exit(app.exec ())
信号类
信号类需要是QtCore.Signal()类的变量,一般我们定义信号,是在类方法的上面进行:
1 2 class Button (QWidget ): clicked=Signal(Qt.MouseButton)
然后,我们就可以设置信号的发出:emit
1 2 def mousePressEvent (self.event ): self.clicked.emit(event.button())
完整代码如下,这个Button将返回按下的鼠标按键类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Button (QWidget ): clicked=Signal(Qt.MouseButton) def __init__ (self ): super (Button, self).__init__() self.clicked.connect(self.PrintE) @Slot() def PrintE (self,arg ): print (arg) def mousePressEvent (self,event ): self.clicked.emit(event.button()) App=QApplication() button=Button() button.show() sys.exit(App.exec ())
Signal的构造函数可以接收一个元组或者一个Python类型或是C类型的列表:
1 2 3 4 signal1 = Signal(int) # Python types signal2 = Signal(QUrl) # Qt Types signal3 = Signal(int, str, int) # more than one type signal4 = Signal((float,), (QDate,)) # optional types
除此之外,它还可以接收定义信号名称的命名参数名。如果没有传递任何信息,则新信号将与赋值给它的变量具有相同的名称。
1 2 3 4 signal5 = Signal(int , name='rangeChanged' ) rangeChanged.emit(...)
Signal还带有可选参数,比如sumResult=Signal(int,arguments=['sum'])
槽类
QObject派生类中的slot应该由装饰器@QtCore.Slot()表示。同样,要定义Signal,只需传递类似QtCore.Signal()类的类型。
1 2 3 @Slot(str ) def slot_function (self, s ): ...
Slot()也接受名称和结果关键字。result关键字定义了将返回的类型,可以是C或Python类型。name关键字的行为与Signal()中的相同。如果没有传递任何名称,则新插槽将具有与正在装饰的函数相同的名称。
重载信号与槽
我们举个简单的栗子,来使用信号与槽。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import sysfrom PySide6.QtWidgets import QApplication,QPushButtonfrom PySide6.QtCore import QObject,Signal,Slotclass Communicate (QObject ): speak=Signal((int ,),(str ,)) def __init__ (self,parent=None ): super (Communicate, self).__init__() self.speak[int ].connect(self.say_something) self.speak[str ].connect(self.say_something) @Slot(int ) @Slot(str ) def say_something (self,arg ): if isinstance (arg,int ): print ("This is a number: " ,arg) elif isinstance (arg,str ): print ("This is a String: " ,arg) if __name__ == '__main__' : app=QApplication(sys.argv) someone=Communicate() someone.speak.emit(10 ) someone.speak[str ].emit("Hello everybody" )