PyQt5——信号与槽的高级玩法

信号与槽的高级玩法

高级自定义信号与槽

所谓高级自定义信号与槽,指的是我们可以自己喜欢的方法定义信号与槽函数,并传递参数。自定义信号的一般流程如下:

  1. 定义信号
  2. 定义槽函数
  3. 连接信号与槽函数
  4. 发射信号
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys

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.signalCall3)
		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(1)
		self.signal3.emit(1,"text")
		self.signal4.emit([1,2,3,4])
		self.signal5.emit({"name":"Juechen","age":"18"})
		self.signal6[int,str].emit(1,"text")
		self.signal6[str].emit("text")

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

	def signalCall2(self,val):
		print("signal2 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()
signal1 emit
signal2 emit, value: 1
signal3 emit ,value: 1 text
signal4 emit, value: [1, 2, 3, 4]
signal5 emit, value: {'name': 'Juechen', 'age': '18'}
signal6 emit, value: 1 text
signal6 overload emit, value: text

使用自定义参数

我们经常需要给槽函数传递自定义参数的情况。但是clicked信号是没有参数,但是槽函数需要参数。

使用lambda表达式

# -*- coding:utf-8 -*-
from PyQt5.QtWidgets import QMainWindow, QPushButton, QWidget, QMessageBox, QApplication, QHBoxLayout
import sys

class WinForm(QMainWindow):
	def __init__(self, parent=None):
		super(WinForm,self).__init__(parent)
		button1 = QPushButton("Button 1")
		button2 = QPushButton("Button 2")

		button1.clicked.connect(lambda: self.onButtonClick(1))
		button2.clicked.connect(lambda : self.onButtonClick(2))

		layout = QHBoxLayout()
		layout.addWidget(button1)
		layout.addWidget(button2)

		main_frame = QWidget()
		main_frame.setLayout(layout)
		self.setCentralWidget(main_frame)

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


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

onButtonClick()函数处理从两个按钮传来的信号。使用lambda表达式传递按钮数字给槽函数,也可以传递其他任何东西,甚至是按钮控件本身。

partial函数

使用functools中的partial函数。

button1.clicked.connect(partial(self.onButtonClick,1))
button2.clicked.connect(partial(self.onButtonClick,2))

装饰器信号与槽

所谓装饰器信号与槽,就是通过装饰器的方法来定义信号和槽函数。

@PyQt5.QtCore.pyqtSlot(参数)
def on_发送者对象名称_发射信号名称(self, 参数):
    pass

这种方法有效的前提是下面的函数已经执行了:

QMetaObject.connectSlotsByName(QObject)
# -*- conding:utf-8 -*-

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

class CustWidget(QWidget):
	def __init__(self, parent=None):
		super(CustWidget, self).__init__(parent)
		self.okButton = QPushButton("OK",self)
		# 使用setObjectName设置对象名称
		self.okButton.setObjectName("okButton")
		layout = QHBoxLayout()
		layout.addWidget(self.okButton)
		self.setLayout(layout)
		QMetaObject.connectSlotsByName(self)

	@pyqtSlot()
	def on_okButton_clicked(self):
		print("点击了ok按钮")

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

在这里插入图片描述

QMetaObject.connectSlotsName(QObject)

它是在PyQt5中根据信号名称自动连接到槽函数的核心代码。这行代码用来将QObject中的子孙的某些信号按照其objectName连接到相应的槽函数。

# -*- coding:utf-8 -*-

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

class CustWidget(QWidget):
	def __init__(self, parent=None):
		super(CustWidget, self).__init__(parent)
		self.okButton = QPushButton("OK", self)

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

	def okButton_clikced(self):
		print("单击了OK按钮")


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

信号与槽的断开与连接

# -*- coding:utf-8 -*-

from PyQt5.QtCore import *

class SignalClass(QObject):
	# 声明无参数的信号
	signal1 = pyqtSignal()
	# 声明带一个int类型参数的信号
	
	signal2 = pyqtSignal(int)

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

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

		# 将信号2连接到signcall
		self.signal2.connect(self.signal1)
		# 发射信号
		self.signal1.emit()
		self.signal2.emit(1)
		# 断开signall、signal2 信号与各槽函数的连接
		self.signal1.disconnect(self.sin1Call)
		self.signal1.disconnect(self.sin2Call)
		self.signal2.disconnect(self.signal1)

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

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



	def sin1Call(self):
		print("signal-1 emit")

	def sin2Call(self):
		print("signal-2 emit")

if __name__ == '__main__':
	signal = SignalClass()
signal-1 emit
signal-2 emit
signal-1 emit
signal-2 emit
signal-1 emit
signal-2 emit

使用Qt Designer 进行页面显示与业务逻辑分类

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'MainWinSignalSlog02.ui'
#
# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(715, 225)
        self.controlsGroup = QtWidgets.QGroupBox(Form)
        self.controlsGroup.setGeometry(QtCore.QRect(10, 20, 451, 151))
        self.controlsGroup.setObjectName("controlsGroup")
        self.widget = QtWidgets.QWidget(self.controlsGroup)
        self.widget.setGeometry(QtCore.QRect(10, 40, 411, 30))
        self.widget.setObjectName("widget")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.label = QtWidgets.QLabel(self.widget)
        self.label.setObjectName("label")
        self.horizontalLayout.addWidget(self.label)
        self.numberSpinBox = QtWidgets.QSpinBox(self.widget)
        self.numberSpinBox.setObjectName("numberSpinBox")
        self.horizontalLayout.addWidget(self.numberSpinBox)
        self.styleCombo = QtWidgets.QComboBox(self.widget)
        self.styleCombo.setObjectName("styleCombo")
        self.styleCombo.addItem("")
        self.styleCombo.addItem("")
        self.styleCombo.addItem("")
        self.horizontalLayout.addWidget(self.styleCombo)
        self.label_2 = QtWidgets.QLabel(self.widget)
        self.label_2.setObjectName("label_2")
        self.horizontalLayout.addWidget(self.label_2)
        self.printButton = QtWidgets.QPushButton(self.widget)
        self.printButton.setObjectName("printButton")
        self.horizontalLayout.addWidget(self.printButton)
        self.widget1 = QtWidgets.QWidget(self.controlsGroup)
        self.widget1.setGeometry(QtCore.QRect(10, 100, 201, 30))
        self.widget1.setObjectName("widget1")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widget1)
        self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.previewStatus = QtWidgets.QCheckBox(self.widget1)
        self.previewStatus.setObjectName("previewStatus")
        self.horizontalLayout_2.addWidget(self.previewStatus)
        self.previewButton = QtWidgets.QPushButton(self.widget1)
        self.previewButton.setObjectName("previewButton")
        self.horizontalLayout_2.addWidget(self.previewButton)
        self.resultGroup = QtWidgets.QGroupBox(Form)
        self.resultGroup.setGeometry(QtCore.QRect(470, 20, 231, 151))
        self.resultGroup.setObjectName("resultGroup")
        self.resultLabel = QtWidgets.QLabel(self.resultGroup)
        self.resultLabel.setGeometry(QtCore.QRect(20, 30, 191, 101))
        self.resultLabel.setObjectName("resultLabel")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "打印控件"))
        self.controlsGroup.setTitle(_translate("Form", "打印控制"))
        self.label.setText(_translate("Form", "打印份数:"))
        self.styleCombo.setItemText(0, _translate("Form", "A3"))
        self.styleCombo.setItemText(1, _translate("Form", "A4"))
        self.styleCombo.setItemText(2, _translate("Form", "A5"))
        self.label_2.setText(_translate("Form", "纸张类型:"))
        self.printButton.setText(_translate("Form", "打印"))
        self.previewStatus.setText(_translate("Form", "全屏预览"))
        self.previewButton.setText(_translate("Form", "预览"))
        self.resultGroup.setTitle(_translate("Form", "操作结果"))
        self.resultLabel.setText(_translate("Form", "<html><head/><body><p><br/></p></body></html>"))

import sys
from PyQt5.QtWidgets import *
from MainWinSignalSlog02 import Ui_Form
from PyQt5.QtCore import pyqtSignal, Qt

class MyMainWindow(QMainWindow,Ui_Form):
	helpSignal = pyqtSignal(str)
	printSignal = pyqtSignal(list)

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

	def __init__(self,parent=None):
		super(MyMainWindow, self).__init__(parent)
		self.setupUi(self)
		self.initUI()

	def initUI(self):
		self.helpSignal.connect(self.showHelpMessage)
		self.printSignal.connect(self.printPaper)
		self.previewSignal[str].connect(self.previewPaper)
		self.previewSignal[int,str].connect(self.previewPaperWithArgs)
		self.printButton.clicked.connect(self.emitPrintSignal)
		self.previewButton.clicked.connect(self.emitPreviewSignal)

	# 发射预览信号
	def emitPreviewSignal(self):
		if self.previewStatus.isChecked() == True:
			self.previewSignal[int,str].emit(1080,"Full Screen")
		elif self.previewStatus.isChecked() == False:
			self.previewSignal[str].emit("Preview")


	# 发射打印信号
	def emitPrintSignal(self):
		pList = []
		pList.append(self.numberSpinBox.value())
		pList.append(self.styleCombo.currentText())
		self.printSignal.emit(pList)


	def printPaper(self,list):
		self.resultLabel.setText("打印: "+"份数: " + str(list[0]) + "纸张: "+str(list[1]) )


	def previewPaperWithArgs(self, style, text):
		self.resultLabel.setText(str(style) + text)

	def previewPaper(self,text):
		self.resultLabel.setText(text)

	# 重载按键事件
	
	def keyPressEvent(self, event):
		if event.key() == Qt.Key_F1:
			self.helpSignal.emit("help message")

	# 显示帮助信息
	def showHelpMessage(self, message):
		self.resultLabel.setText(message)
		self.statusBar().showMessage(message)

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

在这里插入图片描述

多线程中的信号与槽的使用

# -*- coding:utf-8 -*-

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

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_())
thread1==>6
thread1==>5
thread1==>4
thread1==>3
thread1==>2
thread1==>1
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值