Learning Qt 5! (2):信号槽

本文深入探讨了Qt的信号槽机制,包括基本概念、Qt5中的新语法、自定义信号槽的实现步骤及注意事项。通过代码示例展示了信号与槽的连接、发射过程,以及如何利用Lambda表达式简化槽函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天学习了 Qt 学习之路 2(4):信号槽 & Qt 学习之路 2(5):自定义信号槽
回过头来再次学习Qt 学习之路 2(16):深入 Qt5 信号槽新语法。(待看)

所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,用自己的一个函数(成为槽(slot))来处理这个信号。

在 Qt 5 中,QObject::connect()有五个重载。一般的情况中connect()函数有四个参数:sender, signal, receiver 和 slot。
一个代码实例,当button发出clicked信号,调用lambda表达式(关于lambda表达式看C++11 新特性:Lambda 表达式):

// !!! Qt 5
#include <QApplication>
#include <QPushButton>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QPushButton button("Quit");
    QObject::connect(&button, &QPushButton::clicked, [](bool) {
        qDebug() << "You clicked me!";
    });
    button.show();

    return app.exec();
}

一开始忘了#include <QDebug>,运行出错,QDebug invalid use。但是将
qDebug() << "You clicked me!"改为qDebug( "You clicked me!")却又可以。Why?

自定义信号槽部分的代码提醒了自己要去复习C++了!

newspaper.h:定义了Newspaper类。需要特别注意的是其中的signals块。

signals 块所列出的,就是该类的信号。信号就是一个个的函数名,返回值是 void(因为无法获得信号的返回值,所以也就无需返回任何值),参数是该类需要让外界知道的数据。信号作为函数名,不需要在 cpp 函数中添加任何实现。

还不太理解send()是何时被调用?emit又是什么作用?

Newspaper类的send()函数比较简单,只有一个语句emit newPaper(m_name);。emit 是 Qt 对 C++ 的扩展,是一个关键字(其实也是一个宏)。emit 的含义是发出,也就是发出newPaper()信号。感兴趣的接收者会关注这个信号,可能还需要知道是哪份报纸发出的信号?所以,我们将实际的报纸名字m_name当做参数传给这个信号。当接收者连接这个信号时,就可以通过槽函数获得实际值。这样就完成了数据从发出者到接收者的一个转移。

////////// newspaper.h
class Newspaper : public QObject
{
    Q_OBJECT
public:
    Newspaper(const QString & name) :
        m_name(name)
    {
    }

    void send()
    {
        emit newPaper(m_name);
    }

signals:
    void newPaper(const QString &name);

private:
    QString m_name;
};

reader.h:定义了Reader类。槽函数其实就是receiveNewspaper()。

Qt 5 中,任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数。与信号函数不同,槽函数必须自己完成实现代码。槽函数就是普通的成员函数,因此作为成员函数,也会受到 public、private 等访问控制符的影响。(我们没有说信号也会受此影响,事实上,如果信号是 private 的,这个信号就不能在类的外面连接,也就没有任何意义。)private 的槽函数在 Qt5 的新语法情况下是无法通过编译的。

////////// reader.h
#include <QObject>
#include <QDebug>

class Reader : public QObject
{
    Q_OBJECT
public:
    Reader() {}

    void receiveNewspaper(const QString & name)
    {
        qDebug() << "Receives Newspaper: " << name;
    }
};

明白了Newspapaer类和Reader类的定义,main.cpp就好理解了。

////////// main.cpp
#include <QCoreApplication>

#include "newspaper.h"
#include "reader.h"

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    Newspaper newspaper("Newspaper A");
    Reader reader;
    QObject::connect(&newspaper, &Newspaper::newPaper,
                     &reader,    &Reader::receiveNewspaper);
    newspaper.send();

    return app.exec();
}

总结自定义信号槽的注意事项:

  1. 发送者和接收者都需要是QObject的子类(当然,槽函数是全局函数、Lambda 表达式等无需接收者的时候除外);
  2. 使用 signals 标记信号函数,信号是一个函数声明,返回 void,不需要实现函数代码;
    槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响;
  3. 使用 emit 在恰当的位置发送信号;
  4. 使用QObject::connect()函数连接信号和槽。

Q&A:
1.“Newspaper(const QString & name):m_name(name)”中的 m_name(name)”是什么意思?

这个是 C++ 语法,叫做“成员初始化列表”,例如 m_name(name) 作用相当于在构造函数中添加这么一句:m_name = name。但是,初始化列表的执行是在构造函数的实际语句之前进行的。

PS. 复习C++!!!也许需要一本C++ Primer ?

2.Newspaper(const QString & name) 中为什么用const QString & name?

这是标准 C++ 的内容,说明参数是一个引用,并且函数不改变参数值。这种写法符合软件工程的要求,并且能够提高性能。

3.信号槽具体的实现机制?

参考这里:http://www.devbean.net/2012/12/how-qt-signals-and-slots-work/以及http://www.devbean.net/2012/12/how-qt-signals-and-slots-work-qt5/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值