Python Qt GUI设计:信号与槽的使用方法(基础篇—7)

1、信号与槽的概念

信号(signal)和槽(slot)是Qt的核心机制,也是在PyQt编程中对象之间进行通信的机制。在创建事件循环之后,通过建立信号和槽的连接就可以实现对象之间的通信。当信号发射(emit)时,连接的槽函数将会自动执行。

信号(signal)是在特定情况下被发射(emit)的一种通告。GUI程序设计的主要内容就是对界面上各组件发射的特定信号进行响应,只需要知道什么情况下发射了哪些信号,然后合理地去响应和处理这些信号就可以了。

槽(slot)实质上是一个函数,可以被直接调用,是对信号响应的函数。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数会被自动执行。

在Qt编程中,通过Qt信号和槽机制对鼠标或键盘在界面上的操作进行响应处理。例如,对鼠标单击按钮的执行处理信号的操作。

PyQt的窗口控件类中有很多内置信号,开发者也可以添加自定义信号。信号与槽具有如下特点:

一个信号可以连接多个槽;

一个信号可以连接另一个信号;

信号参数可以是任何Python类型;

一个槽可以监听多个信号;

信号与槽的连接方式可以是同步连接,也可以是异步连接;

信号与槽的连接可能会跨线程;

信号可能会断开。

2、信号与槽的基础函数

2.1、创建信号函数

本文仅描述主要的信号函数,具体详情可参照官方文档。

PyQt的内置信号是自动定义的。使用 PyQt5.QtCore.pyqtSignal()函数可以为QObject创建一个信号,使用pyqtSingnal()函数可以把信号定义为类的属性。pyqtSignal()函数信息如下图所以:

2.2、连接信号函数

使用connect()函数可以把信号绑定到槽函数上。connect()函数信息如下图所示:

2.3、断开信号函数

使用disconnect()函数可以解除信号与槽函数的绑定。disconnect()函数信息如下图所示:

2.4、发射信号函数

使用emit()函数可以发射信号。emit()函数信息如下图所示:

3、信号和槽的使用方法

信号与槽有三种使用方法,第一种是内置信号与槽的使用,第二种是自定义信号与槽的使用,第三种是装饰器的信号与槽的使用。由于第三种方法本质上是第一种方法的衍生,因此这里简要介绍前两种方法的使用。

Qt Designer中提供了一些最基础的信号和槽设置方法,在实际的项目开发中,信号和槽最佳的使用方式是Qt Designer和编程相结合,才能提高开发效率。

3.1、内置信号与槽的使用

所谓内置信号与槽的使用,是指在发射信号时,使用窗口控件的函数,而不是自定义的函数。在信号与槽中,可以通过 QObject.signal.connect将一个QObject的信号连接到另一个QObject的槽函数。

可以在【编辑->Edit Signal/slot】中进行信号和槽设置。

进入信号槽编辑模式,可以直接在发射者(“Button"按钮)上按住鼠标左键不放,拖动到接收者(Form窗体)上,这样就建立起了连接,如下图所示:

接着会弹出“配置连接"对话框,如下图所示:

可以看到按钮控件会发射很多内置信号和槽,选择所需信号,然后单击“OK"按钮,就会生成对应的槽函数处理。

例如,我想实现单击按钮关闭窗口的效果,所以这里勾选“显示从QWidget继承的信号和槽"复选框。

在左侧按钮的信号栏里选择clicked()信号,在右侧的Form槽函数中选择close(),这意味着对按钮单击会发射clicked信号,这个信号会被Form窗体的槽函数close()捕捉到,并触发该窗体的close行为(也就是关闭该窗体)。

连接信号和槽成功后,会发现在Edit Signal/slot(编辑信号/槽)模式下,所创建的信号和槽关系的连线是红色的,如下图所示:

接着将UI界面转换为Python文件,这里我使用Eric 6编译,不再赘述,效果如下所示:

拓展学习:Python Qt GUI设计:将UI文件转换为Python文件的三种妙招(基础篇—2)

UI文件编译后代码如下所示:

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Form(object):

    def setupUi(self, Form):

        Form.setObjectName("Form")

        Form.resize(383, 276)

        self.pushButton = QtWidgets.QPushButton(Form)

        self.pushButton.setGeometry(QtCore.QRect(140, 120, 93, 28))

        self.pushButton.setObjectName("pushButton")

        self.retranslateUi(Form)

        self.pushButton.clicked.connect(Form.close)

        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):

        _translate = QtCore.QCoreApplication.translate

        Form.setWindowTitle(_translate("Form", "Form"))

        self.pushButton.setText(_translate("Form", "Button"))

if __name__ == "__main__":

    import sys

    app = QtWidgets.QApplication(sys.argv)

    Form = QtWidgets.QWidget()

    ui = Ui_Form()

    ui.setupUi(Form)

    Form.show()

    sys.exit(app.exec_())

代码中,通过connect函数连接按钮的clicked()信号和槽函数Form.close(),如下所示:

self.pushButton.clicked.connect(Form.close)

运行程序,按钮是信号发射者,当单击按钮之后会发射一个信号,通过这行代码程序内部的通信机制知道这个按钮的单击事件被连接到窗体的关闭事件上,然后通知接收者窗体,可以运行槽函数close(),实现窗口关闭。

3.2、自定义信号与槽的使用

自定义信号与槽是指在发射信号时,不使用窗口控件的函数,而是使用自定义的函数(简单地说,就是使用pyqtSignal类实例发射信号)。

之所以要使用自定义信号与槽,是因为通过内置函数发射信号有自身的缺陷,主要是以下三点:

内置函数只包含一些常用的信号,有些信号的发射找不到对应的内置函数;

内置函数只有在特定情况下(如按钮的点击事件)才能发射这种信号;

内置函数传递的参数是特定的,不可以自定义。使用自定义的信号函数则没有这些缺陷。

在PyQt5编程中,自定义信号与槽的适用范围很灵活。例如,因为业务需求,在程序中的某个地方需要发射一个信号,传递多种数据类型(实际上就是传递参数),然后在槽函数中接收传递过来的数据,这样就可以非常灵活地实现一些业务逻辑。

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

定义信号

定义槽函数

连接信号与槽函数

发射信号

3.2.1、定义信号

使用pyqtSingnal()函数可以把信号定义为类的属性,示例代码如下所示:

  #无参数的信号

  signal1=pyqtSignal()

  #带一个参数(整数)的信号

  signal2=pyqtSignal(int)

  #带两个参数(整数,字符串)的信号

  signal3=pyqtSignal(int,str)

  #带一个参数(列表)的信号

  signal4=pyqtSignal(list)

  #带一个参数(字典)的信号

  signal5=pyqtSignal(dict)

  #带(整数 字符串)或者(字符串)的信号

  signal6=pyqtSignal([int,str],[str])

3.2.2、定义槽函数

定义一个槽函数,它有多个不同的输入参输数,示例代码如下所示:

  def signalCall1( self ):

    print("signal1 emit")

  def signalCall2( self,val ):

    print('signal2 emit,value:',val)

  def signalCall3( self,val,text ):

    print('signall3 emit,value:',val,text)

  def signalCall4( self,val ):

    print('signal4 emit,value:',val)

  def signalCall5( self,val ):

    print('signal5 emit,value',val)

  def signalCall6( self,val,text ):

    print('signal6 emit,value',val,text)

  def signalCall7( self,val ):

    print('signal6 ovetload emit',val)

3.2.3、连接信号与槽函数

使用connect()函数可以把信号绑定到槽函数上,示例代码如下所示:

    #信号与槽函数的链接

    self.signal1.connect(self.signalCall1)

    self.signal2.connect(self.signalCall2)

    self.signal3.connect(self.signalCall3)

    self.signal4.connect(self.signalCall4)

    self.signal5.connect(self.signalCall5)

    self.signal6[int,str].connect(self.signalCall6)

    self.signal6[str].connect(self.signalCall7)

3.2.4、发射信号

使用emit()函数可以发射信号,示例代码如下所示:

    #信号发射

    self.signal1.emit()

    self.signal2.emit(1)

    self.signal3.emit(1,'第三个')

    self.signal4.emit([1,2,3,4])

    self.signal5.emit({"name":'JIA','age':'21'})

    self.signal6[int,str].emit(1,"第六")

    self.signal6[str].emit('第六')

3.2.5、实例

将上述片段代码,整合,非常简单,各位可以看着理解。

from PyQt5.QtCore import QObject,pyqtSignal

class CusSignal(QObject):

  #无参数的信号

  signal1=pyqtSignal()

  #带一个参数(整数)的信号

  signal2=pyqtSignal(int)

  #带两个参数(整数,字符串)的信号

  signal3=pyqtSignal(int,str)

  #带一个参数(列表)的信号

  signal4=pyqtSignal(list)

  #带一个参数(字典)的信号

  signal5=pyqtSignal(dict)

  #带(整数 字符串)或者(字符串)的信号

  signal6=pyqtSignal([int,str],[str])

  def __init__(self,parent=None):

    super(CusSignal, self).__init__(parent)

    #信号与槽函数的链接

    self.signal1.connect(self.signalCall1)

    self.signal2.connect(self.signalCall2)

    self.signal3.connect(self.signalCall3)

    self.signal4.connect(self.signalCall4)

    self.signal5.connect(self.signalCall5)

    self.signal6[int,str].connect(self.signalCall6)

    self.signal6[str].connect(self.signalCall7)

    #信号发射

    self.signal1.emit()

    self.signal2.emit(1)

    self.signal3.emit(1,'第三个')

    self.signal4.emit([1,2,3,4])

    self.signal5.emit({"name":'JIA','age':'21'})

    self.signal6[int,str].emit(1,"第六")

    self.signal6[str].emit('第六')

  #槽函数

  def signalCall1( self ):

    print("signal1 emit")

  def signalCall2( self,val ):

    print('signal2 emit,value:',val)

  def signalCall3( self,val,text ):

    print('signall3 emit,value:',val,text)

  def signalCall4( self,val ):

    print('signal4 emit,value:',val)

  def signalCall5( self,val ):

    print('signal5 emit,value',val)

  def signalCall6( self,val,text ):

    print('signal6 emit,value',val,text)

  def signalCall7( self,val ):

    print('signal6 ovetload emit',val)

if __name__ == '__main__':

  custSignal=CusSignal()

运行效果如下所示:

关于信号与槽的使用方法就讲到这了,在后面的实践中我们再细聊,感兴趣小伙伴可看看以下的拓展学习链接~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • PyQt5:PyQt5 信号与槽(PyQt5的事件处理机制) 一、事件 在事件模型,有三个参与者:事件源、事件目标...
    gongdiwudu阅读 663评论 0 0
  • 引自:https://blog.51cto.com/9291927/2070398 Qt高级——Qt信号槽机制源码...
    Magic11阅读 3,802评论 1 12
  • 写在前面 在界面搭建时,我们需要很多触发事件。比如,鼠标右击,我们希望弹出对话框;点击退出的按钮,界面就会关闭或者...
    锅盖666阅读 569评论 0 0
  • 信号和槽是用于对象之间的通信的,这是Qt的核心。为此Qt引入了一些关键字,他们是slots、signals、emi...
    诗人和酒阅读 601评论 0 2
  • 1、概述 信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检...
    你的社交帐号昵阅读 45,228评论 0 9