Qt学习笔记4:信号与槽(Signal & Slot)


信号与槽是Qt的一大创新,也是Qt编程的基础。本文记录一下该机制的学习笔记。

信号(Signal)

信号(Signal)是定义在类里面的一个函数,必须在函数前加入关键字signals,可以将其理解为宏,这个signals涉及到qt的另一个核心机制(模板元编程)。当拥有信号的类声明了一个对象时,该对象便有了发送该信号的能力,当然,该类的派生类也具有该能力。定义信号函数时,返回值必须是void,可以有形参,但是没有成员限定访问符的限定,我认为它是public,但是好像是真没有,定义一个signals:

signals:
   void selectionChange(int index);

槽(Slots)

槽(Slots)就是对信号响应的函数。它是一个函数,与一般的C++函数是一样的,可以定义在类的任何部分(public、private 或 protected),可以具有任何参数,也可以被直接调用。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。定义一个Slots:

public slots:
   void setNewNum(int index);  

连接(Connect)

信号与槽关联是用 QObject::connect() 函数实现的,其基本格式是:

QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));

connect() 是 QObject 类的一个静态函数,而 QObject 是所有 Qt 类的基类,在实际调用时可以忽略前面的限定符,所以可以直接写为:

connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));

其中,SIGNAL 和 SLOT 是 Qt 的宏,sender 是发射信号的对象的名称,signal() 是信号名称。信号可以看做是特殊的函数,需要带括号,有参数时还需要指明参数。receiver 是接收信号的对象名称,slot() 是槽函数的名称,需要带括号,有参数时还需要指明参数。

原型

static QMetaObject::Connection connect(const QObject *sender, const char *signal,const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);

static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,const QObject *receiver, const QMetaMethod &method,
Qt::ConnectionType type = Qt::AutoConnection);

inline QMetaObject::Connection connect(const QObject *sender, const char *signal,const char *member, Qt::ConnectionType type = Qt::AutoConnection) const;

第一个参数为发射信号的对象,例如后面的dlg;

第二个参数是要发射的信号,例如后面的SIGNAL(dlgReturn(int));

第三个参数是接受信号的对象,例如后面的this,表明是本部件,即Widget,当这个参数是this时,可以将其省略掉,因为在第三个函数中,该参数默认为this;

第四个参数是要执行的槽.

第五个参数一般使用默认值,在满足某些特殊需求的时候可能需要手动设置。

  • Qt::AutoConnection: 默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。

  • Qt::DirectConnection:槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程。效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能会造成奔溃。

  • Qt::QueuedConnection:槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。

  • Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。

  • Qt::UniqueConnection:这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接。

写法

Qt的connect函数有多重写法,为了方便演示,这里先自定义一个button。

class MyButton : public QWidget
{
    Q_OBJECT
public:
    explicit MyButton(QWidget *parent = nullptr);

signals:
    void sigClicked();
    void sigClicked(bool check);
};
  • 第一种写法:老式写法
connect(m_pBtn,SIGNAL(sigClicked()),this,SLOT(onClicked()));

connect(m_pBtn,SIGNAL(sigClicked(bool)),this,SLOT(onClicked(bool)));

该写法的缺点是书写麻烦,优点是清晰明确。

  • 第二种写法:Qt5新写法
connect(m_pBtn, static_cast<void (MyButton::*)(bool)>(&MyButton::sigClicked), this, &Widget::onClicked);
//或
connect(m_pBtn, QOverload<bool>::of(&MyButton::sigClicked),this,&Widget::onClicked);
  • 第三种写法:lambda函数写法
connect(m_pBtn, QOverload<bool>::of(&MyButton::sigClicked),

               [=](bool check){
                /* do something.. */

                });

connect(m_pBtn, static_cast<void (MyButton::*)(bool)>(&MyButton::sigClicked), this, [=](bool check){
                 //do something

                 });

当我们用lambda表达式的时候,槽的接收者QObject是可以省略不写的,这时候Qt会默认发射者与接收者属于同一个QObject。

连接方式

信号(Signal)与槽(Slots)的连接方式有多种:

  • 一个信号可以连接多个槽
connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(addFun(int));
connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(updateStatus(int));
  • 多个信号可以连接同一个槽
connect(ui->rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
  • 一个信号可以连接另外一个信号
connect(spinNum, SIGNAL(valueChanged(int)), this, SIGNAL (refreshInfo(int));
  • 严格的情况下,信号与槽的参数个数和类型需要一致,至少信号的参数不能少于槽的参数。如果不匹配,会出现编译错误或运行错误。
  • 在使用信号与槽的类中,必须在类的定义中加入宏 Q_OBJECT。
  • 当一个信号被发射时,与其关联的槽函数通常被立即执行,就像正常调用一个函数一样。只有当信号关联的所有槽函数执行完毕后,才会执行发射信号处后面的代码。

参考文献(Reference)

Qt信号与槽机制详解

信号与槽机制

qt中的 connect 函数

QT中的connect用法总结

QT 信号槽connect写法

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

i胡说

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

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

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

打赏作者

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

抵扣说明:

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

余额充值