PyQt5-信號與槽


信號與槽我們之前案例中已涉及,信號(Signal)和槽(Slot)是Qt中的核心機制,也是PyQt變成中對象之間進行通信的機制;

在Qt中,每一個QObject對象和PyQt中所有繼承自QWidget的控件都支持信號和槽;

擋信號發射時,連接槽函數將會被自動執行(與事件和回調函數類似); PyQt5中信號和槽通過connect()方法來連接;

PyQt中針對窗口類控件有很多內置的信號,也可以自定義信號;信號與槽有以下幾個特點:

1、一個信號可以連接多個槽函數

2、一個信號可以連接另一個信號

3、一個槽可以監聽多個信號

4、信號和槽的連接可能會跨線程

5、連接方式可以是同步或者異步

6、信號與槽可以是多對多關系

信號的定義:

PyQt來自定義一個信號,則使用PyQt5.QtCore.pyqtSignal()函數完成,使用該函數可以將信號定義為類的一個屬性;

信號必須在類創建時定義,不能在類定以后作為類的屬性動態添加進去;types參數表示定義信號時參數的數據類型,namc參數

表示信號名字,該參數缺省時使用類的屬性名字;pyqtSignal()函數可以傳遞多個參數,並指定信號傳遞參數的類型,參數類型是標准的Python數據類型(字符串、日期、布爾類型,數字,列表,元組和字典)

信號操作:

使用connect()方法來將信號和槽函數綁定;disconnect()函數可以解除綁定;

emit()方法用於發射信號;

例如:

 1 #信號與槽(QTabWidget略)
 2 from PyQt5.QtWidgets import  QComboBox,QTableView,QAbstractItemView,QHeaderView,QTableWidget, QTableWidgetItem, QMessageBox,QListWidget,QListWidgetItem, QStatusBar,  QMenuBar,QMenu,QAction,QLineEdit,QStyle,QFormLayout,   QVBoxLayout,QWidget,QApplication ,QHBoxLayout, QPushButton,QMainWindow,QGridLayout,QLabel
 3 from PyQt5.QtGui import QIcon,QPixmap,QStandardItem,QStandardItemModel,QCursor,QFont,QBrush,QColor
 4 from PyQt5.QtCore import QStringListModel,QAbstractListModel,QModelIndex,QSize,Qt,QObject,pyqtSignal
 5 
 6 import sys
 7 class SiganlObj(QObject):
 8      sendMsg=pyqtSignal(object) #定義信號
 9 
10      def __init__(self):
11          super(SiganlObj, self).__init__()
12      def run(self):
13          self.sendMsg.emit("Hello")#發射信號
14 
15 class TypeSlot(QObject):#定義槽對象
16      def __init__(self):
17          super(TypeSlot, self).__init__()
18      def get(self,msg):#定義槽函數
19          print(">>",msg)
20 
21 if __name__=='__main__':
22     send=SiganlObj()
23     slot=TypeSlot()
24     send.sendMsg.connect(slot.get)#綁定信號和槽函數
25     send.run()#發信號

 再次修改上面實例:

例如,通過按鈕來發送消息:

 1 #信號與槽(QTabWidget略)
 2 from PyQt5.QtWidgets import  QComboBox,QTableView,QAbstractItemView,QHeaderView,QTableWidget, QTableWidgetItem, QMessageBox,QListWidget,QListWidgetItem, QStatusBar,  QMenuBar,QMenu,QAction,QLineEdit,QStyle,QFormLayout,   QVBoxLayout,QWidget,QApplication ,QHBoxLayout, QPushButton,QMainWindow,QGridLayout,QLabel
 3 from PyQt5.QtGui import QIcon,QPixmap,QStandardItem,QStandardItemModel,QCursor,QFont,QBrush,QColor
 4 from PyQt5.QtCore import QStringListModel,QAbstractListModel,QModelIndex,QSize,Qt,QObject,pyqtSignal
 5 
 6 import sys
 7 class SiganlObj(QObject):
 8      sendMsg=pyqtSignal(object,object) #定義信號(無參數或者多個參數都可以)
 9 
10      def __init__(self):
11          super(SiganlObj, self).__init__()
12      def run(self):
13          self.sendMsg.emit("Hello",'JONES')#發射信號
14 
15 class TypeSlot(QObject):#定義槽對象
16      def __init__(self):
17          super(TypeSlot, self).__init__()
18      def get(self,msg,s):#定義槽函數
19          print(">>",msg,s)
20 
21 class Win(QWidget):
22     def __init__(self,parent=None):
23         super(Win, self).__init__(parent)
24         self.btn=QPushButton("點擊",self)
25         self.btn.clicked.connect(self.btnFn)#點擊按鈕,執行btnFn方法
26         self.send = SiganlObj()#信號對象
27         self.slot = TypeSlot()#槽對象
28         self.send.sendMsg.connect(self.slot.get)  # 綁定信號和槽函數
29     def btnFn(self):
30         self.send.run()  # 發信號
31 
32 if __name__=='__main__':
33 
34     app=QApplication(sys.argv)
35     win = Win()
36     win.show()
37     sys.exit(app.exec_())

 例如:點擊按鈕發送多個消息,定義多個槽

 1 #信號與槽(QTabWidget略)多個信號與多個槽
 2 from PyQt5.QtWidgets import  QComboBox,QTableView,QAbstractItemView,QHeaderView,QTableWidget, QTableWidgetItem, QMessageBox,QListWidget,QListWidgetItem, QStatusBar,  QMenuBar,QMenu,QAction,QLineEdit,QStyle,QFormLayout,   QVBoxLayout,QWidget,QApplication ,QHBoxLayout, QPushButton,QMainWindow,QGridLayout,QLabel
 3 from PyQt5.QtGui import QIcon,QPixmap,QStandardItem,QStandardItemModel,QCursor,QFont,QBrush,QColor
 4 from PyQt5.QtCore import QStringListModel,QAbstractListModel,QModelIndex,QSize,Qt,QObject,pyqtSignal
 5 
 6 import sys
 7 #信號
 8 class ObjSignal(QObject):
 9     msg_1=pyqtSignal()#無參數消息
10     msg_2=pyqtSignal([int],[str])#一個參數的消息,參數為str或者int類型
11     msg_3=pyqtSignal(str,list)#兩個參數消息
12     msg_4=pyqtSignal(str,dict)
13 
14 #
15 class ObjSlot(QObject):
16     def __init__(self):
17         super(ObjSlot, self).__init__()
18     def slot_1(self):
19         print("無參數的槽!")
20 
21     def slot_2(self,param):
22         print("[str/int]參數的槽!>>",param)
23 
24     def slot_2_1(self, param):
25         print("[str/int]參數的槽!>>", param)
26 
27     def slot_3(self,param1,param2):
28         print("str +list參數的槽!>>",param1,param2)
29 
30     def slot_4(self,str,dict):
31         print("str,dict參數的槽!",str,dict)
32 
33 
34 
35 class Win(QWidget):
36     def __init__(self,parent=None):
37         super(Win, self).__init__(parent)
38         self.btn=QPushButton("點擊",self)
39         self.signal = ObjSignal()  # 信號對象
40         self.solt = ObjSlot()  # 槽對象
41 
42         self.signal.msg_1.connect(self.solt.slot_1)#無參數
43         self.signal.msg_2[int].connect(self.solt.slot_2)#str/int一個參數
44         self.signal.msg_2[str].connect(self.solt.slot_2_1)  # str/int一個參數
45         self.signal.msg_3.connect(self.solt.slot_3)#str,int 兩個參數
46         self.signal.msg_4.connect(self.solt.slot_4)#str,dict,str兩個參數
47 
48         self.btn.clicked.connect(self.btnFn)#點擊按鈕,執行btnFn方法
49 
50     def btnFn(self):
51         #self.signal.msg_1.connect(self.solt.slot_1)#注意:如果在這個位置來連接,此時會出現,點擊一次 結果顯示一次,點擊第二次,顯示兩次,第三次,則4.。。。。
52         self.signal.msg_1.emit()
53         self.signal.msg_2.emit('abc')
54         self.signal.msg_2.emit(10)
55         self.signal.msg_3.emit('A',[10,20,30,40])
56         self.signal.msg_4.emit('字典參數',{"a":"ABC","b":"SDF"})
57 
58 if __name__=='__main__':
59 
60     app=QApplication(sys.argv)
61     win = Win()
62     win.show()
63     sys.exit(app.exec_())

注意上面的實例中,消息與槽的連接代碼位置放在不同地方是有差異的;也要注意:不允許參數pyqtSignal([int,str],[str,int])這種可選參數,【int,str】即表示該位置參數類型既可以是int也可以是str類型;

 

例如,使用自定義參數

 1 #信號與槽(QTabWidget略)自定義參數
 2 from PyQt5.QtWidgets import  QComboBox,QTableView,QAbstractItemView,QHeaderView,QTableWidget, QTableWidgetItem, QMessageBox,QListWidget,QListWidgetItem, QStatusBar,  QMenuBar,QMenu,QAction,QLineEdit,QStyle,QFormLayout,   QVBoxLayout,QWidget,QApplication ,QHBoxLayout, QPushButton,QMainWindow,QGridLayout,QLabel
 3 from PyQt5.QtGui import QIcon,QPixmap,QStandardItem,QStandardItemModel,QCursor,QFont,QBrush,QColor
 4 from PyQt5.QtCore import QStringListModel,QAbstractListModel,QModelIndex,QSize,Qt,QObject,pyqtSignal
 5 
 6 import sys
 7 class Win(QWidget):
 8     def __init__(self,parent=None):
 9         super(Win, self).__init__(parent)
10         self.btn1=QPushButton("點擊1",self)
11         self.btn1.move(20,40)
12         self.btn1.clicked.connect(lambda :self.btnFn(1))#點擊按鈕,執行btnFn方法
13 
14         self.btn2 = QPushButton("點擊2", self)
15         self.btn2.move(140,40)
16         self.btn2.clicked.connect(lambda: self.btnFn(2))  # 點擊按鈕,執行btnFn方法
17 
18 
19 
20     def btnFn(self,flag):
21         if flag==1:
22             print("點擊了第一個按鈕")
23         else:
24             print("點擊了第二個按鈕")
25 
26 
27 if __name__=='__main__':
28 
29     app=QApplication(sys.argv)
30     win = Win()
31     win.show()
32     sys.exit(app.exec_())

 

 

裝飾器信號與槽:

即通過裝飾器來定義信號和槽函數;

1 @PyQt5.QtCore.pyqtSlot(參數)
2 def on_發送者對象名稱_發射信號名稱(self,參數):
3 pass

 以上定義的信號和槽有效,則前提是執行了

QMetaObject.connectSlotsByName(QObject)

"發送者對象名稱"即讓按鈕、下拉列表以及其他各種組件通過setObjectName方法設置的名稱,

例如:

1 def __init__(self,parent=None):
2     self.okButton.clicked.connect(self.okButton_clicked)
3 def okButton_clicked(self):
4     print('單擊ok按鈕!')

等同於下面幾行代碼:

1 @QtCore.pyqtSlot()
2 def on_okButton_clicked(self):
3     print('單擊了ok按鈕')

 

信號與槽的連接與斷開

槽的斷開通過disconnect來斷開連接;

 1 #信號與槽(QTabWidget略)信號的斷開與連接
 2 from PyQt5.QtWidgets import  QComboBox,QTableView,QAbstractItemView,QHeaderView,QTableWidget, QTableWidgetItem, QMessageBox,QListWidget,QListWidgetItem, QStatusBar,  QMenuBar,QMenu,QAction,QLineEdit,QStyle,QFormLayout,   QVBoxLayout,QWidget,QApplication ,QHBoxLayout, QPushButton,QMainWindow,QGridLayout,QLabel
 3 from PyQt5.QtGui import QIcon,QPixmap,QStandardItem,QStandardItemModel,QCursor,QFont,QBrush,QColor
 4 from PyQt5.QtCore import QStringListModel,QAbstractListModel,QModelIndex,QSize,Qt,QObject,pyqtSignal
 5 
 6 import sys
 7 class SlotObj(QObject):
 8     # 信號
 9     slot_1 = pyqtSignal()
10     slot_2 = pyqtSignal(str)
11     def __init__(self,parent=None):
12         super(SlotObj, self).__init__(parent)
13         '''
14         注意:容易犯錯的地方是,將
15         信號定義在該方法中;信號應該定義在類中
16         '''
17         #
18         self.slot_1.connect(self.call_1)
19         self.slot_2[str].connect(self.call_2)
20 
21         #發送消息
22         self.slot_1.emit()
23         self.slot_2.emit("HAHA!")
24 
25         #斷開連接
26         self.slot_1.disconnect(self.call_1)
27 
28         #再次發送消息
29         self.slot_1.emit()#已經將其斷開,則無法發送信息號
30         self.slot_2.emit("HAHA!")
31 
32     def call_1(self):
33         print('call_1')
34     def call_2(self,str):
35         print('call_2A>>',str)
36 
37 if __name__=='__main__':
38     SlotObj()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM