PyQt-信号和槽

目录

 

什么是信号与槽?

信号与槽例子

信号和槽的关联方法

信号的类型

Qt型信号

Python型信号

短路信号

非短路信号

一个信号关联多个槽的例子

连接公用槽的方法

偏函数应用程序(partial function application)

通过PyQt来了解那个信号调用了该槽

打断和阻止操作

QObject.disconnect()

QObject.blockSignals()


什么是信号与槽?

在Qt和PyQt中有两种通信机制:

  • 低级事件处理机制(low-level event-handling mechanism)

  • 高级机制(high-level mechanism)

前者是大部分GUI通用的机制,后者是Qt独有机制,也就是信号和槽。这一章我们主要对信号和槽进行说明

在PyQt中每一个部件(QWidget)都支持信号和槽机制。用户在与GUI进行交互时几乎每一个操作都会触发相应的信号,这些信号默认会被忽略掉,只有连接了槽的信号才会别处理。

在PyQt中槽可以是部件预设的一些方法,也可以是任何可调用对象和方法。

信号与槽例子

import sys
from PySide2 import QtCore
from PySide2 import QtWidgets


class Form(QtWidgets.QDialog):

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

        dial = QtWidgets.QDial()
        dial.setNotchesVisible(True)
        spinbox = QtWidgets.QSpinBox()

        layout = QtWidgets.QHBoxLayout()
        layout.addWidget(dial)
        layout.addWidget(spinbox)
        self.setLayout(layout)

        self.connect(dial, QtCore.SIGNAL("valueChanged(int)"),
                     spinbox.setValue)
        self.connect(spinbox, QtCore.SIGNAL("valueChanged(int)"),
                     dial, QtCore.SLOT("setValue(int)"))
        self.setWindowTitle("Signals and Slots")


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

运行结果:

     

这里创建了两个部件QDial和QSpinBox,然后使用connect将这两个部件的信号和槽分别进行关联,这样当我们改变其中任何一个部件的值时,另一个部件也会随之改变。虽然两个部件信号和槽相互关联,但是并不存在死循环的问题,因为像这种之变化类型的槽在执行是会先检测值是否发生了变化,如果有就执行,没有就不会做任何事。

信号和槽的关联方法

上面的例子中valueChanged(int)方法作为信号,setValue(int)就是槽,信号和槽的关联方法主要有三种:

  1. self.connect(QWidget, SIGNAL("signalSignature"), functionName())
  2. self.connect(QWidget, SIGNAL("signalSignature"), instance.methodName)
  3. self.connect(QWidget, SIGNAL("signalSignature"), instance, SLOT("slotSignature"))

上面的例子中分别使用了2和3的方法,实际应用中2是比较常用的方法。

信号的类型

Qt型信号

Qt预设的信号

Python型信号

在PyQt中自定义的信号,PyQt中使用QObject.emit()方法自定义。

短路信号

没有参数的信号

非短路信号

含有参数的

一个信号关联多个槽的例子

import sys
from PySide2 import QtCore
from PySide2 import QtWidgets


if sys.version_info[:2] < (2, 5):
    def partial(func, arg):
        def callme():
            return func(arg)
        return callme
else:
    from functools import partial


class Form(QtWidgets.QDialog):

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

        button1 = QtWidgets.QPushButton("One")
        button2 = QtWidgets.QPushButton("Two")
        button3 = QtWidgets.QPushButton("Three")
        button4 = QtWidgets.QPushButton("Four")
        button5 = QtWidgets.QPushButton("Five")
        self.label = QtWidgets.QLabel("Click a button...")

        layout = QtWidgets.QHBoxLayout()
        layout.addWidget(button1)
        layout.addWidget(button2)
        layout.addWidget(button3)
        layout.addWidget(button4)
        layout.addWidget(button5)
        layout.addStretch()
        layout.addWidget(self.label)
        self.setLayout(layout)

        self.connect(button1, QtCore.SIGNAL("clicked()"), self.one)
        self.button2callback = partial(self.anyButton, "Two")
        self.connect(button2, QtCore.SIGNAL("clicked()"),
                     self.button2callback)
        self.button3callback = lambda who="Three": self.anyButton(who)
        self.connect(button3, QtCore.SIGNAL("clicked()"),
                     self.button3callback)
        self.connect(button4, QtCore.SIGNAL("clicked()"), self.clicked)
        self.connect(button5, QtCore.SIGNAL("clicked()"), self.clicked)

        self.setWindowTitle("Connections")

    def one(self):
        self.label.setText("You clicked button 'One'")

    def anyButton(self, who):
        self.label.setText("You clicked button '%s'" % who)

    def clicked(self):
        button = self.sender()
        if button is None or not isinstance(button, QtWidgets.QPushButton):
            return
        self.label.setText("You clicked button '%s'" % button.text())


app = QtWidgets.QApplication(sys.argv)
form = Form()
form.show()
app.exec_()

运行结果:

在这个例子中创建5个按钮,当点击其中一个按钮时,最右侧的文本就会发生改变,提示用户当前所执行的的操作。

连接公用槽的方法

上面的例子中每一个按钮对应不同的操作,会产生不同的信号,但能否将他们关联到同一个槽中呢?

要实现这种操作一般有两种方法:

  1. 偏函数应用程序(partial function application)

  2. 通过PyQt来了解那个信号调用了该槽

第一种方法可以是把信号和按钮的名字使用partial()方法封装到一起。也可以使用lambda函数,按钮名字作为参数这样的方法实现。

在一个槽的内部,总是可以通过sender()方法获取信号来源的QObject对象。所以第二种方法利用这一点在槽中获取被点击按钮的名字。

打断和阻止操作

QObject.disconnect()

可以取消连接操作

QObject.blockSignals()

用来阻止信号发射

猜你喜欢

转载自blog.csdn.net/xiaoqiao11770/article/details/82050894
今日推荐