当前位置:   article > 正文

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

pyqt5 信号和槽

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执行完其自身的代码后,继续在这里往下运行

    做另外一些处理...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

需要注意的是:

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

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_())

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

运行效果如下:
20221115002626

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

  • 使用connect()方法将信号和槽关联起来, 见上述代码示例
self.btn_clicked_signal.connect(self.on_btn_click)
  • 1
  • 使用emit()方法来发射信号,可以携带参数,见上述代码示例
self.btn_clicked_signal.emit(event.x(), event.y())
  • 1
  • 使用disconnect()方法也可以让信号和槽断开关联
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/838909
推荐阅读
相关标签
  

闽ICP备14008679号