一、簡單Demo
簡單使用信號和槽(之前常用的使用方式):
class DemoWin(QMainWindow):def __init__(self):super().__init__()self.initUI()def initUI(self):self.resize(400, 250)self.btn = QPushButton("發送信號", self)# 發送一個clicked信號,綁定槽函數是self.onClick()self.btn.clicked.connect(self.onClick)# 添加窗口標題self.setWindowTitle("SignalDemo")# 槽函數,接收btn的clicked信號def onClick(self):self.btn.setText("接收到信號")self.btn.setStyleSheet("max-width:200px;min-width:200px;")
這是最簡單的信號和槽的使用方法,其中clicked事件是button的默認事件,我們將其綁定到自定義的onClick槽函數即可。
二、自定義信號Demo
?
# 導入信號
from PyQt5.QtCore import Qt, QObject, pyqtSignal# 自定義信號類
class MySignal(QObject):sendmsg = pyqtSignal(object) # 定義一個信號,object表示傳遞一個參數(object是python中的基類)def run(self):self.sendmsg.emit("Hello PyQt5") # 觸發信號,并傳遞一個string參數class MySlot(QObject):# 定義槽函數,接收一個string參數def slot(self, msg):print("接收到的信息是:", msg)if __name__ == '__main__':mySignal = MySignal()mySlot = MySlot()# 將信號和槽進行綁定mySignal.sendmsg.connect(mySlot.slot)#mySignal.sendmsg.disconnect(mySlot.slot) # 斷開連接
# 觸發信號 mySignal.run() # 打印 "接收到的信息是: Hello PyQt5"
?
1)首先創建一個pyqtSignal信號實例(參數對應槽的參數的類型)
2)使用connect綁定信號和槽(使用后可以手工斷開連接,使用mySignal.sendmsg.disconnect(mySlot.slot))
3)觸發信號
三、信號傳遞數據(多個參數)
# 導入信號
from PyQt5.QtCore import Qt, QObject, pyqtSignal# 自定義信號類
class MySignal(QObject):sendmsg = pyqtSignal(object, int, dict) # 定義一個信號,傳遞三個參數def run(self):self.sendmsg.emit("Hello PyQt5", 50, {"name": "leo"}) # 觸發信號,并傳遞三個參數,參數類型在信號定義時指定class MySlot(QObject):# 定義槽函數,接收一個string參數def slot(self, msg,age,name):print("接收到的信息是:", msg)print("接收到的年齡是:", age)print("接收到的名稱是:", name['name'])if __name__ == '__main__':mySignal = MySignal()mySlot = MySlot()# 將信號和槽進行綁定mySignal.sendmsg.connect(mySlot.slot)# 觸發信號mySignal.run() # 打印 "接收到的信息是: Hello PyQt5"
?
可以看到,我們在定義信號的時候指定了對應槽函數的參數類型,并在觸發信號時傳入實際的參數,這樣槽函數就可以接受到數據了。
四、多對多綁定,綁定信號
信號和槽是可以N對N綁定的,也就是說在參數一致的情況下,一個信號可以綁定多個槽函數,一個槽函數也可以綁定多個信號。
信號還可以與信號綁定,例如B信號綁定了A信號,A信號和A槽函數綁定,則觸發B最終觸發A槽函數。
Demo:
?
# 導入信號
from PyQt5.QtCore import Qt, QObject, pyqtSignal# 自定義信號類
class MySignal(QObject):signal1 = pyqtSignal(object)signal2 = pyqtSignal(object,object)def __init__(self):super(MySignal, self).__init__()# signal1綁定多個槽函數(slot1和slot2)self.signal1.connect(self.slot1)self.signal1.connect(self.slot2)# signal2綁定signal1self.signal2.connect(self.signal1)self.signal1.emit(1) # 觸發slot1和slot2self.signal2.emit(2,3) # 雖然目前signal2和signal1綁定,但是signal2.emit的參數還是必須和signal定義時一致def slot1(self, num):print("slot1 " + str(num))def slot2(self, num):print("slot2 " + str(num))if __name__ == '__main__':mySignal = MySignal()
?
特別注意,signal2和signal1綁定后,槽函數的參數應該是signal1一致,而signal2.emit的參數應該是signal2定義時的參數類型一致。
signal2和signal1綁定時,觸發signal2的參數個數要多余signal1。例如signal1有一個int參數,那么singal2的第一個參數也必須是int,后面多的參數沒用。
上述代碼的輸出結果:
slot1 1
slot2 1
slot1 2 # 這里的2就是signal2傳遞給signal1的第一個參數,然后signal1將其傳遞給了slot1
slot2 2
?