PyQt5教程-Martin 扩展Signals


本章将试图通过python来对signal的行为进行更改,或者创建自定义的signals。

改变Signal的data

Signals传给Slots的值是固定的,理论上我们无法更改。但现在我们可以通过python的一些语言特性来完成。

1. 取消数据

目的:Signals会传送数据给Slots,但现在Slots不需要这个数据。

方案:使用另一个function来wrap:

lambda x: fn()  # 现在x不会被传递到fn中

2. 增加数据

目的:除了signals发送的数据,Slots还需要其他的数据

方案:还是wrap一个函数

lambda x: fn(x, some_more_data)

在loop时使用此方法,一定要注意variables的行为,这时候最后的值可能会覆盖前方的值。

这在中碰到过。

for i in range(n):
    lambda: fn(i)

每次迭代的时候,i都会指向新的值,如果我们的函数fn立即执行了i,则这没有问题。但关键在于,我们在进行布局的时候,我们并没有立即从i中取出我们想要的值,则fn只是暂时保存了i的引用。当我们在event loop中触发fn执行的时候,其先找到i,然后去看它指向的数据,这个时候loop已经执行完,这个值永远是n

解决方案:

for i in range(n):
    lambda i=i: fn(i)

解决方案也很简单,也是利用python的特性。python函数创建的时候,如果参数有默认值,为了效率考虑,其会先把默认值执行一遍,取到值和函数的定义存放在一起备用。所以如果将i指定成默认值,其会在每个循环的时候都运行一般和相关的函数定义保存到一起,这就解决了上面的问题。

自定义Signals

实际上,signals就是QObject的类属性(几乎所有能碰到的Qt类都是它的子类),创建时使用函数pyqtSignal创建。

以下使用找到的博客中的例子来进行说明:

# py example1.py
# 来源:https://blog.csdn.net/zhulove86/article/details/52563131
# author:Tony Zhu
import sys
from PyQt5.QtCore import pyqtSignal, Qt
from PyQt5.QtWidgets import (
    QWidget, QApplication, QGroupBox, QPushButton, QLabel,
    QCheckBox, QSpinBox, QHBoxLayout, QComboBox, QGridLayout
)


class SignalEmit(QWidget):

    helpSignal = pyqtSignal(str)  # str表示这个signal发送的信息将是str
    printSignal = pyqtSignal(list)
    # 这里是复合信号,第一个会带有两个值,第二个将带有1个值,可以使用Signal[int, str]和Signal[str]
    #   得到每个部分
    previewSignal = pyqtSignal([int, str], [str])

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):

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

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

        # 设置自定义Signals的slots
        self.helpSignal.connect(self.showHelpMesage)
        self.printSignal.connect(self.printPaper)
        self.previewSignal[str].connect(self.previewPaper)
        self.previewSignal[int, str].connect(self.previewPaperWithArgs)
        # 这里将自定义signals的发送信息作为slots链接到存在的signals上
        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 creatControls(self, title):
        # 一个带有标题的盒子,用来作为容器承载更多的widgets,主要用来划分区域
        self.controlsGroup = QGroupBox(title)
        self.printButton = QPushButton("打印")
        self.previewButton = QPushButton("预览")
        numberLabel = QLabel("打印份数:")
        paperLabel = QLabel("纸张类型:")
        # 原来checkBox可以直接给文本来当做label。。
        self.previewStatus = QCheckBox("全屏预览")
        # spin box就是一个数字轮盘
        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(paperLabel, 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() is True:
            self.previewSignal[int, str].emit(1080, "Full Screen")
        elif self.previewStatus.isChecked() is 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):
        # QWidget自带的方法(event handler),用于在继承时进行改写,
        #   接受的event是关于键盘的事件
        # 在event loop中被时刻监听
        if event.key() == Qt.Key_F1:
            # 如果按下了F1,则helpsignal信号将发送,其发送的消息是字符串
            self.helpSignal.emit("Help Message")

    def showHelpMesage(self, message):
        # 是helpSignal信号的slot,接受的是上面方法中的Help Message字符串,
        #   其行为是将此字符串打印到resultLabel上
        self.resultLabel.setText(message)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    dispatch = SignalEmit()
    sys.exit(app.exec_())

结果:



文章作者: Luyiyun
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Luyiyun !
评论
评论
  目录