RHZ'S BLOG | 个人分享

  • 首页
  • 笔记
  • 小日常
  • 音乐
  • 读书
  • 软件分享
YOLO
  1. 首页
  2. 笔记
  3. Code
  4. 正文

PyQt5|自定义信号的使用[D]

2022年8月16日 352点热度 2人点赞 0条评论

1.信号与槽的一些特点和功能

在PyQt5中,信号与槽的使用有如下一些特点:

  • 一个信号可以关联多个槽函数
  • 一个信号也可以关联其他信号
  • 信号的参数可以是任何Python数据类型
  • 一个槽函数可以和多个信号关联
  • 关联可以是直接的(同步)或排队的(异步)
  • 可以在不同线程之间建立关联
  • 信号与槽也可以断开关联
  • 关联可以是直接的(同步)或排队的(异步)。
  • 可以在不同线程之间建立关联。
  • 信号与槽也可以断开关联。

使用PyQt5.QtCore.pyqtSignal()为一个类定义新的信号。要自定义信号,类必须是QObject类的子类。pyqtSignal()的句法是:

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

信号可以带有参数types,后面的参数都是一些可选项,基本不使用。

信号需要定义为类属性,这样定义的信号是未绑定(unbound)信号。当创建类的实例后,PyQt5会自动将类的实例与信号绑定,这样就生成了绑定的(bound)信号。这与Python语言从类的函数生成绑定的方法的机制是一样的。
一个绑定的信号(也就是类的实例对象的信号)具有connect()、disconnect()和emit()这3个函数,分别用于关联槽函数、断开与槽函数的关联、发射信号。

2.自定义信号使用示例

## 自定义信号与槽的演示
import sys
from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal


#定义的类Human是从QObject继承而来的,它定义了两个信号,两个信号都需要定义为类的属性。
class Human(QObject):
    ##定义一个带str类型参数的信号
    nameChanged = pyqtSignal(str)
    ## overload型信号有两种参数,一种是int,另一种是str
    ageChanged = pyqtSignal([int], [str])


    def __init__(self, name='Mike', age=10, parent=None):
        super().__init__(parent)
        self.setAge(age)
        self.setName(name)


    def   setAge(self, age):
        self.__age= age
        self.ageChanged.emit(self.__age)    #发射int参数信号
        if age<=18:
            ageInfo="你是 少年"
        elif (18< age <=35):
            ageInfo="你是 年轻人"
        elif (35< age <=55):
            ageInfo="你是 中年人"
        elif (55< age <=80):
            ageInfo="您是 老人"
        else:
            ageInfo="您是 寿星啊"
        self.ageChanged[str].emit(ageInfo)    #发射str参数信号


    def setName(self, name):
        self.__name = name
        self.nameChanged.emit(self.__name)#通过信号的emit()函数发射信号。


class Responsor(QObject):
    @pyqtSlot(int)
    def do_ageChanged_int(self, age):
        print("你的年龄是:"+str(age))


    @pyqtSlot(str)
    def do_ageChanged_str(self, ageInfo):
        print(ageInfo)


##   @pyqtSlot(str)
    def do_nameChanged(self, name):
        print("Hello, "+name)


if  __name__ == "__main__":    ##测试程序
    print("**创建对象时**")
    boy=Human("Boy",16)
    resp=Responsor()
    boy.nameChanged.connect(resp.do_nameChanged)


    ## overload的信号,两个槽函数不能同名,关联时需要给信号加参数区分
    boy.ageChanged.connect(resp.do_ageChanged_int)
#默认参数,int型
    boy.ageChanged[str].connect(resp.do_ageChanged_str)    #str型参数


    print("\n **建立关联后**")
    boy.setAge(35)        #发射两个ageChanged信号
    boy.setName("Jack")   #发射nameChanged信号

#在程序中可以使用disconnect()函数断开信号与槽的关联
    boy.ageChanged[str].disconnect(resp.do_ageChanged_str)    #断开关联
    print("\n **断开ageChanged[str]的关联后**")
    boy.setAge(10)        #发射两个ageChanged信号

运行程序human.py,在Python Shell中显示如下的运行结果:

**创建对象时**
  **建立关联后**
你的年龄是:35
你是 年轻人
Hello, Jack
 **断开ageChanged[str]的关联后**
你的年龄是:10

从运行结果中可以看到:
· 创建对象时虽然也发射信号,但还未建立关联,所以无响应;
· 建立关联后,3个信号关联的槽函数都响应了;
· 断开关联后,断开关联的槽函数无响应了

@pyqtSlot修饰符的作用
在PyQt5中,任何一个函数都可以作为槽函数,但有时也需要使用@pyqtSlot修饰符说明函数的参数类型,以使信号与槽之间能正确关联。
@pyqtSlot()修饰符用于声明槽函数的参数类型,例如在[B]的示例中,为了使函数on_chkBoxItalic_clicked(self, checked)与窗体上chkBoxItalic复选框的clicked(bool)信号自动建立关联,就使用了@pyqtSlot(bool)进行修饰。
在本例Responsor类的3个槽函数前的@pyqtSlot()修饰符都可以被注释掉,不影响程序的运行结果。因为overload型信号的两个槽函数名称不同,在建立关联时也指定了参数类型。

Human.setAge()函数中发射了两次ageChanged信号,但是使用了不同的参数,分别是int型参数和str型参数,即

self.ageChanged.emit(self.__age)      #int参数信号
self.ageChanged[str].emit(ageInfo)    #str参数信号

3.注意

信号与槽机制是非常好用的,特别是为GUI程序各对象之间的信息传递提供了很方便的处理方法,但是在PyQt5中使用信号与槽时也要注意以下问题。
(1)对于PyQt5中的类的内建overload型信号,一般只为其中一种信号编写槽函数。例如QCheckBox组件有clicked()和clicked(bool)两种信号,可以有针对性地只选择其中一种参数类型的信号编写槽函数。如果使用的overload型信号不是默认参数类型的信号,那么槽函数还需要使用@pyqtSlot()修饰符声明参数类型。
(2)在自定义信号时,尽量不要定义overload型信号。因为Python的某些类型转换为C++的类型时,对于C++来说可能是同一种类型的参数,例如,若定义一个overload型的信号:

valueChanged = pyqtSignal([dict], [list])

dict和list在Python中是不同的数据类型,但是转换为C++后可能就是相同的数据类型了,这可能会出现问题。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: PyQt5 python 信号与槽 自定义信号
最后更新:2022年8月16日

RHZ

即使单枪匹马,我亦勇敢无畏

点赞
< 上一篇
下一篇 >

文章评论

取消回复
归档
  • 2023年2月
  • 2022年12月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年8月
  • 2021年7月

COPYRIGHT © 2022 RHZ的博客. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

渝ICP备2022008933号-1