PyQt: 信号-槽机制

PyQt: 信号-槽机制

信号-槽机制是QT的一个重要特征。该特征的存在可以方便不同对象之间的通信。当一些特定的事件发生时,可以发射一个信号。当该信号与某个或者某些槽连接在一起时,对应的槽会做出响应(执行相关代码)。
如果该信号不与任何槽存在连接,那么什么都不做。这也就是说信号发射之后,并不关心是否有对象去接受这个信号。

信号-槽机制具有以下特点:
1)一个信号可以与多个槽连接;
2)一个信号可以与其他信号连接;
3)信号的参数可以是任意类型;
4)一个槽可以连接多个信号;
5)信号与槽的连接可以断开;
6) 连接可以是同步的也可以是异步的;
7)连接是可以跨线程的。

定义新的信号函数

pyqt5自动地定义内置的信号函数,而新的信号函数需要通过pyqtSignal()来定义成所属类的属性。
一个信号具有三个方法: connect()、disconnect()、emit()。

信号可以被重载,但原有的信号函数会被当做是默认函数。自定义的新信号函数存在多个重载函数时,第一个被认为是默认的信号函数。

PyQt5.QtCore.pyqtSignal(types[, name[, revision=0[, arguments=[]]]])

from PyQt5.QtCore import QObject, pyqtSignal

class Foo(QObject):

    # This defines a signal called 'closed' that takes no arguments.
    closed = pyqtSignal()

    # This defines a signal called 'rangeChanged' that takes two
    # integer arguments.
    range_changed = pyqtSignal(int, int, name='rangeChanged')

    # This defines a signal called 'valueChanged' that has two overloads,
    # one that takes an integer argument and one that takes a QString
    # argument.  Note that because we use a string to specify the type of
    # the QString argument then this code will run under Python v2 and v3.
    valueChanged = pyqtSignal([int], ['QString'])

当一个信号被发射时其传递的任何参数都会被转化成对应的C++类型。当信号的类型没有对应的C++类型时,其会被封装成一种可以使用的类型。因此,在定义新信号的时候需要注意参数类型。

class Foo(QObject):
    # This will cause problems because each has the same C++ signature.
    valueChanged = pyqtSignal([dict], [list])

定义新的槽函数

尽管pyqt5允许任意的可调用函数作为槽函数以接受信号。但有时候函数需要明确的指出某些方法是槽函数并给出相应的C++签名(signature)。在pyqt5中,函数pyqtSlot()承担了这一任务。
PyQt5.QtCore.pyqtSlot(types[, name[, result[, revision=0]]])

from PyQt5.QtCore import QObject, pyqtSlot

class Foo(QObject):

    @pyqtSlot()
    def foo(self):
        """ C++: void foo() """

    @pyqtSlot(int, str)
    def foo(self, arg1, arg2):
        """ C++: void foo(int, QString) """

    @pyqtSlot(int, name='bar')
    def foo(self, arg1):
        """ C++: void bar(int) """

    @pyqtSlot(int, result=int)
    def foo(self, arg1):
        """ C++: int foo(int) """

    @pyqtSlot(int, QObject)
    def foo(self, arg1):
        """ C++: int foo(int, QObject *) """

也可以对同一个函数使用多个decorator。

from PyQt5.QtCore import QObject, pyqtSlot

class Foo(QObject):

    @pyqtSlot(int)
    @pyqtSlot('QString')
    def valueChanged(self, value):
        """ Two slots will be defined in the QMetaObject. """

连接、断开与发射信号

信号可以通过connect()函数与槽相连接。当连接失败时会抛出异常。其中的槽可以使可调用的函数或者其他信号。
connect(slot[, type=PyQt5.QtCore.Qt.AutoConnection[, no_receiver_check=False]])

信号与槽的断开连接通过函数disconnect()实现。当没有指定槽名称时,则默认断开所有连接。
disconnect([slot])

信号函数利用emit()函数来发射信号。
emit(*args)

from PyQt5.QtCore import QObject, pyqtSignal

class Foo(QObject):
    # Define a new signal called 'trigger' that has no arguments.
    trigger = pyqtSignal()

    def connect_and_emit_trigger(self):
        # Connect the trigger signal to a slot.
        self.trigger.connect(self.handle_trigger)

        # Emit the signal.
        self.trigger.emit()

    def handle_trigger(self):
        # Show that the slot has been called.
        print "trigger signal received"

也可以使用关键字参数来建立连接。

act = QAction("Action", self)
act.triggered.connect(self.on_triggered)

act = QAction("Action", self, triggered=self.on_triggered)

act = QAction("Action", self)
act.pyqtConfigure(triggered=self.on_triggered)

传递额外的参数

在编程的时候很多时候并不想重载已有的信号函数,而又想传递额外的参数。额外的参数有时候很有用,特别有时候可以提高模块的重复使用性以减少代码冗余。下面提供了两种可以传递额外参数的方法。

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

from PyQt5.Qt import *
from functools import partial


class customWindow(QWidget):
    def __init__(self):
        super(customWindow, self).__init__()
        self.setWindowTitle('Keep Learning Pyqt')
        self.resize(600,100)
        btn_1 = QPushButton("btn_1")
        btn_2 = QPushButton("btn_2")
        btn_3 = QPushButton("btn_3")
        self.txt = QTextEdit()

        btn_1.clicked.connect(self.btn_1_clicked)
        btn_2.clicked.connect(lambda checked: self.btn_2_clicked(checked, 2)) # it also can receive the signal arguments
        btn_3.clicked.connect(partial(self.btn_3_clicked, 3))

        mainlayout = QHBoxLayout()
        mainlayout.addWidget(btn_1)
        mainlayout.addWidget(btn_2)
        mainlayout.addWidget(btn_3)
        mainlayout.addWidget(self.txt)
        self.setLayout(mainlayout)

#===============define two function to show result========================
    def btn_1_clicked(self):
        str = "Button 1 is clicked by classical method"
        self.txt.setText(str)

#===============use lambda expression to transmit addtional params=======
    def btn_2_clicked(self,checked, n):
        print checked  
        str = "Button {0} is clicked by lambda expression".format(n)
        self.txt.setText(str)

#===============use partial function to transmit addtional params========
    def btn_3_clicked(self, n):
        str = "Button {0} is clicked by partial function".format(n)
        self.txt.setText(str)


if __name__ =="__main__":
     import sys
     app = QApplication(sys.argv)
     myWindow = customWindow()
     myWindow.show()

     app.exec_()

Reference

[1] Support for Signals and Slots
[2] pyqt信号和槽传递额外参数

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值