网络编程
位置:首页>> 网络编程>> 网络编程>> 一文详解PyQt5中信号(Signal)与槽(Slot)

一文详解PyQt5中信号(Signal)与槽(Slot)

作者:SongYuLong的博客  发布时间:2022-06-27 19:53:08 

标签:PyQt5,信号,槽

信号与槽介绍

信号(Signal)与槽(Slot)是Qt中的核心机制,也是在PyQt编程中对象之间进行通信的机制。PyQt的窗口控件类有很多内置信号,开发者也可以添加自定义信号。信号与槽有如下特点:

  • 一个信号可以连接多个槽。

  • 一个信号可以连接另一个信号。

  • 信号参数可以使任何Python类型。

  • 一个槽可以连接到多个信号。

  • 信号与槽的连接方式可以是同步连接,也可以是异步连接。

  • 信号与槽的连接可能会跨线程。

  • 信号可以断开连接。

内置信号与槽的使用

这里演示了内置clicked信号连接槽函数的使用

import sys
from PyQt5.QtWidgets import QPushButton, QApplication, QWidget, QMessageBox

app = QApplication(sys.argv)
widget = QWidget()

def showMsg():
   QMessageBox.information(widget, "信息提示框", "Ok,弹出测试信息")

btn = QPushButton("测试点击按钮", widget)
btn.clicked.connect(showMsg)

widget.show()
sys.exit(app.exec_())

一文详解PyQt5中信号(Signal)与槽(Slot)

自定义信号与槽的使用

import sys
from PyQt5.QtCore import QObject, pyqtSignal

# 信号对象
class QTypeSignal(QObject):
   # 定义一个信号
   sendmsg = pyqtSignal(object)

def __init__(self):
       super(QTypeSignal, self).__init__()

def run(self):
       # 发射信号
       self.sendmsg.emit('Hello PyQt5')

# 槽对象
class QTypeSlot(QObject):
   def __init__(self):
       super(QTypeSlot, self).__init__()

# 槽对象中的槽函数
   def get(self, msg):
       print("QSlot get msg => " + msg)

if __name__ == "__main__":
   send = QTypeSignal()
   slot = QTypeSlot()

# 1
   print("---把信号绑定到槽函数上---")
   send.sendmsg.connect(slot.get)
   send.run()

# 2
   print('---把信号与槽函数断开---')
   send.sendmsg.disconnect(slot.get)
   send.run()

一文详解PyQt5中信号(Signal)与槽(Slot)

自定义信号和内置槽函数

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtCore import Qt

class WinForm (QWidget):
   # 自定义信号,不带参数
   button_clicked_signal = pyqtSignal()

def __init__(self, parent=None):
       super(WinForm, self).__init__(parent)
       self.setWindowTitle("自定义信号和内置槽函数示例")
       self.resize(330, 50)
       btn = QPushButton("关闭", self)

# 连接信号与槽函数
       btn.clicked.connect(self.btn_clicked)

# 接收信号,连接到槽函数
       self.button_clicked_signal.connect(self.close)

def btn_clicked(self):
       # 发送自定义信号,无参数
       self.button_clicked_signal.emit()

if __name__ == "__main__":
   app = QApplication(sys.argv)
   win = WinForm()
   win.show()
   sys.exit(app.exec_())

自定义信号和自定义槽函数

import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

class WinForm(QWidget):
   # 自定义信号,无参数
   button_clicked_signal = pyqtSignal()
   def __init__(self, parent= None):
       super(WinForm, self).__init__(parent)
       self.setWindowTitle("自定义信号和槽函数示例")
       self.resize(350, 50)

btn = QPushButton("关闭", self)
       btn.clicked.connect(self.btn_clicked)
       self.button_clicked_signal.connect(self.btn_close)

def btn_clicked(self):
       self.button_clicked_signal.emit()

def btn_close(self):
       self.close()

if __name__ == "__main__":
   app = QApplication(sys.argv)
   win = WinForm()
   win.show()
   sys.exit(app.exec_())    

自定义有参信号

import sys
from PyQt5.QtCore import pyqtSignal, QObject

class CustSignal(QObject):
   # 声明无参数的信号
   signal1 = pyqtSignal()

# 声明带一个int类型参数的信号
   signal2 = pyqtSignal(int)

# 声明带一个int和一个str类型参数的信号
   signal3 = pyqtSignal(int, str)

# 声明带一个列表类型参数的信号
   signal4 = pyqtSignal(list)

# 声明带一个字典类型参数的信号
   signal5 = pyqtSignal(dict)

# 声明一个多重载版本的信号,包括带int和str类型参数的信号和带str类型参数的信号
   signal6 = pyqtSignal([int,str], [str])

def __init__(self, parent=None):
       super(CustSignal, self).__init__(parent)

# 将信号连接到指定的槽函数
       self.signal1.connect(self.signalCall1)
       self.signal2.connect(self.signalCall2)
       self.signal3.connect(self.signalCall4)
       self.signal4.connect(self.signalCall4)
       self.signal5.connect(self.signalCall5)
       self.signal6[int, str].connect(self.signalCall6)
       self.signal6[str].connect(self.signalCall6OverLoad)

# 发射信号
       self.signal1.emit()
       self.signal2.emit(100)
       self.signal3.emit(200, 'hello')
       self.signal4.emit([1,2,3,4,5,6])
       self.signal5.emit({"name":"xiaowang", "age":"25"})
       self.signal6[int, str].emit(300, 'hello world')
       self.signal6[str].emit('hello pyqt')

def signalCall1(self):
       print('signal1 emit')

def signalCall2(self, val):
       print('signal3 emit, value:', val)

def signalCall3(self, val, text):
       print('signal3 emit, value:', val, text)

def signalCall4(self, val):
       print('signal4 emit, value:', val)

def signalCall5(self, val):
       print('signal5 emit, value:', val)

def signalCall6(self, val, text):
       print('signal6 emit, value:', val, text)

def signalCall6OverLoad(self, val):
       print('signal6 overload emit, value:', val)

if __name__ == "__main__":
   custSignal = CustSignal()

使用自定义信号参数

对于clicked信号来说他是没有参数的,如果连接的槽函数希望可以接收参数,如果直接连接有参数的槽函数会出错,因为信号发出的参数个数一定要大于槽函数接收的参数个数。这里有两种解决方法:

1.使用lambda

2.使用functools模块中的partial函数

import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from functools import partial, partialmethod

class WinForm(QMainWindow):
   def __init__(self, parent=None):
       super(WinForm, self).__init__(parent)
       self.setWindowTitle("有参槽函数接收无参信号的解决方法")

button1 = QPushButton("Button 1")
       button2 = QPushButton("Button 2")

# 对于clicked信号来说他是没有参数的,如果连接的槽函数希望可以接收参数,如果直接连接有参数
       # 的槽函数会出错,因为信号发出的参数个数一定要大于槽函数接收的参数个数。这里有两种解决方法:
       # 1.使用lambda
       # 2.使用functools模块中的partial函数

# 使用lambda
       button1.clicked.connect(lambda: self.onButtonClick(1))

# 使用functools模块中的partial函数
       button2.clicked.connect(partial(self.onButtonClick, 2))

layout = QHBoxLayout()
       layout.addWidget(button1)
       layout.addWidget(button2)
       mainwidget = QWidget()
       mainwidget.setLayout(layout)
       self.setCentralWidget(mainwidget)

def onButtonClick(self, n):
       print("Button {0} 被按下了".format(n))
       QMessageBox.information(self, "信息提示框", 'Button {0} clicked'.format(n))

if __name__ == "__main__":
   app = QApplication(sys.argv)
   win = WinForm()
   win.show()
   sys.exit(app.exec_())

装饰器信号与槽

@PyQt5.QtCore.pyqtSlot(参数)

def on_发送者对象名称_发射信号名称(self, 参数):

pass

必须先执行了这行代码:QtCore.QMetaObject.connectSlotsByName(self)

from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QMessageBox
import sys

# 装饰器信号与槽
# @PyQt5.QtCore.pyqtSlot(参数)
# def on_发送者对象名称_发射信号名称(self, 参数):
#   pass
#
# 必须要先执行这行代码:QtCore.QMetaObject.connectSlotsByName(self)

class CustWidget(QWidget):
   def __init__(self, parent=None):
       super(CustWidget, self).__init__(parent)
       self.setWindowTitle("装饰器信号与槽Demo")
       self.resize(350, 50)

self.okButton = QPushButton("OK", self)

# 使用setObjectName设置对象名称
       self.okButton.setObjectName("okButton")
       layout = QHBoxLayout()
       layout.addWidget(self.okButton)
       self.setLayout(layout)

QtCore.QMetaObject.connectSlotsByName(self)

@QtCore.pyqtSlot()
   def on_okButton_clicked(self):
       print("单击了OK按钮")
       QMessageBox.information(self, "信息提示框", "单击了OK按钮")

if __name__ == "__main__":
   app = QApplication(sys.argv)
   win = CustWidget()
   win.show()
   sys.exit(app.exec_())

信号与槽的断开和连接

import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

# 信号与槽断开连接

class SignalClass(QObject):
   # 声明无参数的信号
   signal1 = pyqtSignal()

# 声明带一个int类型参数的信号
   signal2 = pyqtSignal(int)

def __init__(self, parent=None):
       super(SignalClass, self).__init__(parent)

# 将信号signal1连接到sig1Call和sig2Call这两个槽函数
       self.signal1.connect(self.sig1Call)
       self.signal1.connect(self.sig2Call)

# 将signal2连接到signal1
       self.signal2.connect(self.signal1)

# 发射信号
       self.signal1.emit()
       self.signal2.emit(1)

# 断开signal1,signal2信号与各槽函数的连接
       self.signal1.disconnect(self.sig1Call)
       self.signal1.disconnect(self.sig2Call)
       self.signal2.disconnect(self.signal1)

# 将信号signal1和signal2连接到同一个槽函数sig1Call
       self.signal1.connect(self.sig1Call)
       self.signal2.connect(self.sig1Call)

# 再次发射信号
       self.signal1.emit()
       self.signal2.emit(2)

def sig1Call(self):
       print('signal-1 emit')

def sig2Call(self):
       print('signal-2 emit')

if __name__ == "__main__":
   signal = SignalClass()

多线程中信号与槽的使用

import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import QThread, pyqtSignal

class Main(QWidget):
   def __init__(self, parent=None):
       super(Main, self).__init__(parent)

# 创建一个线程实例并设置名称,变量,信号与槽
       self.thread = MyThread()
       self.thread.setIdentity("thread1")
       self.thread.sinOut.connect(self.outText)
       self.thread.setVal(6)

def outText(self, text):
       print(text)

class MyThread(QThread):

sinOut = pyqtSignal(str)

def __init__(self, parent=None):
       super(MyThread, self).__init__(parent)
       self.identity = None

def setIdentity(self, text):
       self.identity = text

def setVal(self, val):
       self.times = int(val)
       # 执行线程run方法
       self.start()

def run(self):
       while self.times > 0 and self.identity:
           # 发射信号
           self.sinOut.emit(self.identity + "==>" + str(self.times))
           self.times -= 1

if __name__ == '__main__':
   app = QApplication(sys.argv)
   main = Main()
   main.show()
   sys.exit(app.exec_())

来源:https://blog.csdn.net/songyulong8888/article/details/128083678

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com