8. PyQt5信号(signals)和槽(slots)

1. 什么是信号(signals)和槽(slots)?

信号和槽是用于对象之间的通信的,它们是Qt编程的基础,也是Qt的核心。它们可以让编程人员把那些互不了解的对象绑定在一起,来完成对象之间的协同操作。为此 Qt 引入了一些关键字,他们是slots、 signals、 emit,这些都不是 C++关键字,是 Qt 特有的,这些关键字会被 Qt 的 moc转换为标准的 C++语句。

假如我们单击窗口上的一个按钮后想要弹出一个对话框,那么可以将这个按钮的单击信号和自定义的槽关联起来,在这个槽中创建一个对话框并且显示它。这样,单击这个按钮时就会发射信号,进而执行和它关联的槽函数(处理这个信号)来显示一个对话框。

Qt 的部件类中有一些已经定义好了的信号和槽, 通常的作法是子类化部件类,然后添加自已的信号和槽。

2. 信号和槽机制概述

QT/PyQt 使用的C++/Python语言虽然是面向对象的语言,但程序的具体实现代码仍然是由函数来实现的,因此所谓的对象之间的通信,从程序设计的角度来看,就是函数调用的问题,只不过是某个对象的成员函数调用另一个对象的成员函数而已。

从设计模式的角度来看,信号和槽其实就是观察者模式的一种实现,什么是观察者模式,可以参考GOF的设计模式一书。

Qt使用的信号和槽机制的基本思想如下:

  • 创建一个信号,其中创建信号需要遵循一定的规则
  • 当需要调用外部函数时,发送一个信号
  • 此时与该信号相关联的槽便会被调用,槽其实就是一个函数,当然要是函数成为槽是有一定的规则的。
  • 信号和槽的关联是要由程序员来指定的

信号和槽的执行大致过程如下:

定义一个信号:x
定义一个槽函数: void g(...){...}    # g和h都是程序员定义的槽
另一个槽函数:void h(...){...}
关联信号和槽:(x, g)    // 这一步是有程序员指定的
执行函数f时:
f(...)
{
    做一些处理...

    # 信号可以由程序员发射,也可以由系统发射,发射信号就相当于是一个函数调用
    # 这里相当于调用函数g
    发送信号: x

    # 当接收信号的槽函数g执行完其自身的代码后,继续在这里往下运行

    做另外一些处理...
}

需要注意的是:

  • 一个信号可以关联到多个槽上
  • 多个信号也可以关联到同一个槽上
  • 甚至,一个信号还可以关联到另一个信号上。
  • 若信号连接到另一个信号,则当第一个信号发射时,会立即发射第二个信号
  • 如果存在多个槽与某个信号关联,那么当这个信号被发射时,这些槽将会一个接一个按顺序执行,执行顺序与关联顺序相同。

Qt在其类库中已经预定义了很多信号和槽,因此在Qt中

  • 可以仅使用Qt库中预定义的信号和槽
  • 也可以只使用预定义的信号,而使用自定义的槽
  • 也可以使用预定义的槽,来响应自定义的信号
  • 当然,信号和槽也都可以全部自定义

3. 创建自定义的信号和槽

# coding=utf-8

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QGridLayout
from PyQt5.QtCore import pyqtSignal, Qt

class MyWidget(QWidget):
    # 申明一个自定义信号,带2个int类型的参数
    btn_clicked_signal = pyqtSignal(int, int)

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

    def init_ui(self):
        # 创建一个gridlayout用于网格布局
        grid = QGridLayout()
        grid.setSpacing(10)

        # 创建一个label用于展示当前鼠标的位置坐标
        x = y = 0
        self.text = '左键点击窗口, 获取当前鼠标位置坐标 x:{0}, y:{1}'.format(x, y)
        self.label = QLabel(self.text, self)

        # 窗口布局
        grid.addWidget(self.label, 0, 0, Qt.AlignmentFlag.AlignCenter)
        self.setLayout(grid)

        # 关联自定义信号和槽
        self.btn_clicked_signal.connect(self.on_btn_click)

        # 设置鼠标可追踪
        self.setMouseTracking(True)

        # 展示窗口
        self.resize(200, 100)
        self.setWindowTitle('自定义信号和槽示例程序')
        self.show()

    # 自定义的槽函数, 将获取到的鼠标坐标显示出来
    def on_btn_click(self, x, y):
        self.text = '左键点击窗口, 获取当前鼠标位置坐标 x:{0}, y:{1}'.format(x, y)
        self.label.setText(self.text)

    # 重写鼠标按下事件
    def mousePressEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            # 鼠标左键按下时,发射自定义信号
            self.btn_clicked_signal.emit(event.x(), event.y())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    my_widget = MyWidget()
    my_widget.show()
    sys.exit(app.exec_())

运行效果如下:
20221115002626

4. 信号和槽的关联(连接)

  • 使用connect()方法将信号和槽关联起来, 见上述代码示例
self.btn_clicked_signal.connect(self.on_btn_click)
  • 使用emit()方法来发射信号,可以携带参数,见上述代码示例
self.btn_clicked_signal.emit(event.x(), event.y())
  • 使用disconnect()方法也可以让信号和槽断开关联
  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

smart_cat

你的鼓励将是我写作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值