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()

 

posted @ 2018-12-17 16:56  zyg_100  阅读(3618)  评论(0编辑  收藏  举报