Qt的信号和槽机制(笔记)

59 篇文章 1 订阅

信号和插槽

信号和槽用于对象之间的通信。

Qt 的元对象系统使信号和槽成为可能。

GUI 编程中,当我们更改一个小部件时,我们经常希望通知另一个小部件。更一般地说,我们希望任何类型的对象都能够相互通信。

其他工具包使用回调实现这种通信。

Qt 中,我们有一个回调技术的替代方案:我们使用信号和槽。

信号和槽机制是类型安全的:信号的签名必须与接收槽的签名匹配。 

基于字符串的 SIGNAL 和 SLOT 语法将在运行时检测类型不匹配。信号和槽是松散耦合的:发出信号的类既不知道也不关心哪个槽接收信号。

Qt 的信号和槽机制确保如果将信号连接到槽,则将在正确的时间使用信号的参数调用槽。

QObject 或其子类之一(例如 QWidget)继承的所有类都可以包含信号和槽。

槽可以用来接收信号,但它们也是普通的成员函数。就像一个对象不知道是否有任何东西接收到它的信号一样,一个槽也不知道它是否有任何信号连接到它。

您可以将任意数量的信号连接到单个插槽,并且可以将信号连接到任意数量的插槽。甚至可以将一个信号直接连接到另一个信号。 (这将在第一个信号发出时立即发出第二个信号。)

信号是公共访问函数,可以从任何地方发出,但我们建议只从定义信号的类及其子类中发出它们。

当一个信号发出时,连接到它的槽通常会立即执行,就像一个普通的函数调用一样。发生这种情况时,信号和槽机制完全独立于任何 GUI 事件循环。一旦所有槽都返回,将在发出语句之后执行代码。使用排队连接时情况略有不同;在这种情况下,emit 关键字后面的代码将立即继续执行,而 slot 将在稍后执行。

如果多个槽连接到一个信号,则在发出信号时,这些槽将按照它们连接的顺序一个接一个地执行。


 

插槽

插槽是普通的C++函数,可以正常调用;它们唯一的特点是可以将信号连接到它们。

与回调相比,信号和槽的速度稍慢,因为它们提供了更高的灵活性

一般来说,发出一个连接到某些槽的信号,比直接调用接收器慢大约十倍

请注意,定义称为信号或槽的变量的其他库在与基于 Qt 的应用程序一起编译时可能会导致编译器警告和错误。为了解决这个问题,#undef 有问题的预处理器符号。

所有包含信号或槽的类都必须在其声明的顶部提及 Q_OBJECT。它们还必须(直接或间接)从 QObject 派生。

默认情况下,对于您建立的每个连接,都会发出一个信号;为重复连接发出两个信号。您可以通过一次 disconnect() 调用中断所有这些连接。如果您传递 Qt::UniqueConnection 类型,则只有在不重复时才会建立连接。如果已经存在重复(完全相同的信号到相同对象上完全相同的插槽),则连接将失败并且连接将返回 false。


 

例子

class Counter
{
public:
    Counter() { m_value = 0; }

    int value() const { return m_value; }
    void setValue(int value);

private:
    int m_value;
};


#include <QObject>

class Counter : public QObject
{
    Q_OBJECT

public:
    Counter() { m_value = 0; }

    int value() const { return m_value; }

public slots:
    void setValue(int value);

signals:
    void valueChanged(int newValue);

private:
    int m_value;
};

void Counter::setValue(int value)
{
    if (value != m_value) {
        m_value = value;
        emit valueChanged(value);
    }
}

Counter a, b;
    QObject::connect(&a, &Counter::valueChanged,
                     &b, &Counter::setValue);

    a.setValue(12);     // a.value() == 12, b.value() == 12
    b.setValue(48);     // a.value() == 12, b.value() == 48

调用 a.setValue(12) 使 a 发出 valueChanged(12) 信号,b 将在其 setValue() 槽中接收该信号,即调用 b.setValue(12)。然后 b 发出相同的 valueChanged() 信号,但由于没有插槽连接到 b 的 valueChanged() 信号,因此该信号被忽略。

使用lambda表达式

connect(action, &QAction::triggered, engine,
        [=]() { engine->processAction(action->text()); });

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

天天进步2015

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

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

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

打赏作者

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

抵扣说明:

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

余额充值