PyQ5已经自动定义了很多QT自建的信号。但是在实际的使用中为了灵活使用信号与槽机制,可以根据需要自定义信号。通过使用pyqtSignal()方法定义新的信号,新的信号作为类的属性。

自定义signal说明:

新的信号应该定义在QObject的子类中。新的信号必须作为定义类的一部分,不允许将信号作为类的属性在类定义之后通过动态的方式进行添加。通过这种方式新的信号才能自动的添加到QMetaObject类中。这就意味这新定义的信号将会出现在Qt Designer,并且可以通过QMetaObject API实现内省。

自定义信号的发射,通过emit()方法类实现

自定义信号的一般流程如下:

  1. 定义信号
  2. 定义槽函数
  3. 绑定信号和槽
  4. 发射信号

代码示例

import sys
from PyQt5.QtCore import pyqtSignal, QObject, Qt, pyqtSlot
from PyQt5.QtWidgets import QWidget, QApplication, QGroupBox, QPushButton, QLabel, QCheckBox, QSpinBox, QHBoxLayout, QComboBox, QGridLayout


class SignalEmit(QWidget):
    helpSignal = pyqtSignal(str)
    printSignal = pyqtSignal(list)
    #声明一个多重载版本的信号,包括了一个带int和str类型参数的信号,以及带str参数的信号
    previewSignal = pyqtSignal([int,str],[str])
    def __init__(self):
        super().__init__()        
        self.initUI()


    def initUI(self):           

        self.creatContorls("打印控制:")
        self.creatResult("操作结果:")

        layout = QHBoxLayout()
        layout.addWidget(self.controlsGroup)
        layout.addWidget(self.resultGroup)
        self.setLayout(layout)

        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)

        self.setGeometry(300, 300, 290, 150)
        self.setWindowTitle('defined signal')
        self.show()

    def creatContorls(self,title):
        self.controlsGroup = QGroupBox(title)
        self.printButton = QPushButton("打印")
        self.previewButton  = QPushButton("预览")
        numberLabel = QLabel("打印份数:")
        pageLabel = QLabel("纸张类型:")
        self.previewStatus = QCheckBox("全屏预览")
        self.numberSpinBox = QSpinBox()
        self.numberSpinBox.setRange(1, 100)
        self.styleCombo = QComboBox(self)
        self.styleCombo.addItem("A4")
        self.styleCombo.addItem("A5")

        controlsLayout = QGridLayout()
        controlsLayout.addWidget(numberLabel, 0, 0)
        controlsLayout.addWidget(self.numberSpinBox, 0, 1)
        controlsLayout.addWidget(pageLabel, 0, 2)
        controlsLayout.addWidget(self.styleCombo, 0, 3)
        controlsLayout.addWidget(self.printButton, 0, 4)
        controlsLayout.addWidget(self.previewStatus, 3, 0)
        controlsLayout.addWidget(self.previewButton, 3, 1)
        self.controlsGroup.setLayout(controlsLayout)

    def creatResult(self,title):
        self.resultGroup = QGroupBox(title)
        self.resultLabel = QLabel("")
        layout = QHBoxLayout()
        layout.addWidget(self.resultLabel)
        self.resultGroup.setLayout(layout)

    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("Print: "+"份数:"+ 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)
    dispatch = SignalEmit()
    sys.exit(app.exec_())

样例说明:

通过一个模拟打印的界面来详细说明一下关于信号的自定义,在打印的时候可以设定打印的分数,纸张类型,触发“打印”按钮之后,将执行结果显示到右侧;通过全屏预览QCheckBox来选择是否通过全屏模式进行预览,将执行结果显示到右侧。
通过点击F1快捷键,可以显示helpMessage信息。

界面分析:

该界面主要由两个部分组成:一个是打印控制,另一个是操作结果

通过QHBoxLayout组合起来,如下所示:

layout = QHBoxLayout()
layout.addWidget(self.controlsGroup)
layout.addWidget(self.resultGroup)
self.setLayout(layout)

 然后通过creatContorls定义“打印控制”界面,

def creatContorls(self,title):
    self.controlsGroup = QGroupBox(title)
    self.printButton = QPushButton("打印")
    self.previewButton  = QPushButton("预览")
    numberLabel = QLabel("打印份数:")
    pageLabel = QLabel("纸张类型:")
    self.previewStatus = QCheckBox("全屏预览")
    self.numberSpinBox = QSpinBox()
    self.numberSpinBox.setRange(1, 100)
    self.styleCombo = QComboBox(self)
    self.styleCombo.addItem("A4")
    self.styleCombo.addItem("A5")

    controlsLayout = QGridLayout()
    controlsLayout.addWidget(numberLabel, 0, 0)
    controlsLayout.addWidget(self.numberSpinBox, 0, 1)
    controlsLayout.addWidget(pageLabel, 0, 2)
    controlsLayout.addWidget(self.styleCombo, 0, 3)
    controlsLayout.addWidget(self.printButton, 0, 4)
    controlsLayout.addWidget(self.previewStatus, 3, 0)
    controlsLayout.addWidget(self.previewButton, 3, 1)
    self.controlsGroup.setLayout(controlsLayout)

 QSpinBox是一个计数器控件,允许用户选择一个整数值通过单击向上向下或者按键盘上的上下键来增加减少当前显示的值,当然用户也可以输入值。

QComboBox是一个集按钮和下拉选项于一体的控件,也称做下拉列表框。

 然后通过creatResult定义“操作结果”界面:

def creatResult(self,title):
        self.resultGroup = QGroupBox(title)
        self.resultLabel = QLabel("")
        layout = QHBoxLayout()
        layout.addWidget(self.resultLabel)
        self.resultGroup.setLayout(layout)

代码分析:

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

通过pyqtSignal()定义了三个信号,helpSignal,printSignal,previewSignal。其中:
helpSignal 为str参数类型的信号。
printSignal 为list参数类型的信号。
previewSignal为一个多重载版本的信号,包括了一个带int和str类型参数的信号,以及str类行的参数。

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)

绑定信号和槽。

着重说明一下多重载版本的信号的绑定,previewSignal有两个版本previewSignal(str),previewSignal(int,str)。由于存在两个版本,从因此在绑定的时候需要显式的指定信号和槽的绑定关系。

具体如下:
self.previewSignal[str].connect(self.previewPaper) self.previewSignal[int,str].connect(self.previewPaperWithArgs)
其中[str]参数的previewSignal信号绑定previewPaper();[int,str]的previewSignal信号绑定previewPaperWithArgs()

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)

如代码中所示,在信号发射的时候可以传递python数据类型的参数,在本例中传递list类型的参数pList。

def keyPressEvent(self, event):
    if event.key() == Qt.Key_F1:
         self.helpSignal.emit("help message")

通过复写keyPressEvent()方法,将F1快捷键进行功能的拓展。在windows的大部分应用,我们都会使用一些快捷键来快速的完成某些特定的功能。比如F1键,会快速调出帮助界面,那就可以复写keyPressEvent()方法来模拟发送所需的信号,来完成对应任务。

python 自定义Exception python 自定义信号_python 自定义Exception

注意事项:

  1. 自定义的信号在init()函数之前定义
  2. 自定义型号可以传递,str、int、list、object、float、tuple、dict等很多类型的参数
  3. 注意signal和slot的调用逻辑,避免signal和slot之间出现死循环。如在slot方法中继续发射该信号