学习笔记_信号和槽

学习笔记_信号和槽

信号和槽机制(signal and slot)

信号和槽机制用于完成界面操作的相应,是完成任意两个Qt对象之间的通信机制。信号会在某个特定情况或动作下被触发,槽是等同于接受并处理信号的函数。若要将一个窗口部件的变换情况告知另一窗口部件,则向另一窗口部件发送信号。每个Qt对象都包含若各个预定义的信号和槽,当某一特定事件发生时,一个信号被发送,与信号相关联的槽则会相应信号并完成相应的操作。
信号和槽可以自定义。

信号和信号相连,槽相应信号

connect(Object1,SIGNAL(signal1),Object2,SIGNAL(signal2));
connect(Object1,SIGNAL(signal1),Object2,SLOT(slot));
signal如clicked(),slot如showarea()

信号和槽的优点

(1)类型安全。关联的信号和槽的签名必须相同。
(2)松散耦合。减弱Qt对象间的耦合度。
但是,增加了对象间同信的灵活度,但是运行速度较回调函数慢。
通过传递一个信号来调用槽函数将会比直接调用非虚函数运行速度慢10倍。
(1)需要定位接受信号的对象。
(2)安全地历遍所有关联。
(3)编组(Marshal)和解组(unmarshal)传递的参数。
(4)多线程时,信号可能需要排队。

所谓信号槽,实际就是观察者模式。

connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
    QObject::connect(&pushButton,SIGNAL(clicked(bool)),&w,SLOT(show()));
connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type)
    QObject::connect(&pushButton,&QPushButton::clicked,&w,&QWidget::show);
connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type)
    QObject::connect(&pushButton,&QPushButton::clicked,&w,&QWidget::show);
connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)MainWindow *w = new MainWindow;
    QObject::connect(&pushButton,&QPushButton::clicked,[=](){w->show();})
connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type)

关键点

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;
}
  • Q_OBJECT:发送者和接收者都需要是QObject的子类(当然,槽函数是全局函数、Lambda 表达式等无需接收者的时候除外);
  • signal:使用 signals 标记信号函数,信号是一个函数声明,返回 void,不需要实现函数代码;
  • 槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响;
  • emit:使用 emit 在恰当的位置发送信号;
  • 使用QObject::connect()函数连接信号和槽。
  • 由于 moc 只处理头文件中的标记了Q_OBJECT的类声明,不会处理 cpp 文件中的类似声明。因此,如果我们的Newspaper和Reader类位于 main.cpp 中,是无法得到 moc 的处理的。解决方法是,我们手动调用 moc 工具处理 main.cpp,并且将 main.cpp 中的#include "newspaper.h"改为#include "moc_newspaper.h"就可以了。
  • signals 块所列出的,就是该类的信号。信号就是一个个的函数名,返回值是 void(因为无法获得信号的返回值,所以也就无需返回任何值),参数是该类需要让外界知道的数据。信号作为函数名,不需要在 cpp 函数中添加任何实现(我们曾经说过,Qt 程序能够使用普通的 make 进行编译。没有实现的函数名怎么会通过编译?原因还是在 moc,moc 会帮我们实现信号函数所需要的函数体,所以说,moc 并不是单纯的将 Q_OBJECT 展开,而是做了很多额外的操作)。

常见问题:

  • 有重载的信号
    • 解决方法:使用一个函数指针来说明指向哪个信号
      • 定义函数指针
        void (Newspaper:: *newPaperNameDate)(const QString &, const QDate &) = &Newspaper::newPaper;
        QObject::connect(&newspaper, newPaperNameDate, &reader, &Reader::receiveNewspaper);
      • C强制类型转换
        QObject::connect(&newspaper,(void (Newspaper:: *)(const QString &, const QDate &))&Newspaper::newPaper,&reader, &Reader::receiveNewspaper);
      • C++类型转换
        QObject::connect(&newspaper, static_cast<void (Newspaper:: *)(const QString &, const QDate &)>(&Newspaper::newPaper),&reader,&Reader::receiveNewspaper);
  • 带有默认参数的槽函数
    • 解决方法:使用lambda表达式。
      Object::connect(&newspaper,static_cast<void (Newspaper:: )(const QString &)>(&Newspaper::newPaper),[=](const QString &name) { / Your code here. */ });

信号和槽的参数传递

  • 当信号和槽函数的参数数量相同时,它们点的参数类型要完全一致。
  • 当信号和槽函数的参数数量不同时,只能是信号的参数数量大于槽的参数数量而且,前面相同数量的参数类型应该一致,信号中多余的参数被忽略。
  • 在不进行参数传递时信号的参数也应该大于槽的参数。
  • 当槽参数带有默认值的时候,槽的参数可以 大于信号的参数。

信号和槽的连接方式

  1. Qt::AutoConnection
    (Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.
    自动方式,当信号和槽在同一个线程的时候采用DirectConnection,不同线程的时候异步采用QueuedConnection
  2. Qt::DirectConnection
    The slot is invoked immediately when the signal is emitted. The slot is executed in the signalling thread.
    直接连接,在同一个线程的时候使用,信号槽直接触发不需要排队
  3. Qt::QueuedConnection
    The slot is invoked when control returns to the event loop of the receiver’s thread. The slot is executed in the receiver’s thread.
    队列连接,信号和槽不同线程的时候使用,将信号所对应的的槽的执行放入队列之中,等待槽所在线程空闲时执行
  4. Qt::BlockingQueuedConnection
    Same as Qt::QueuedConnection, except that the signalling thread blocks until the slot returns. This connection must not be used if the receiver lives in the signalling thread, or else the application will deadlock.
  5. Qt::UniqueConnection
    This is a flag that can be combined with any one of the above connection types, using a bitwise OR. When Qt::UniqueConnection is set, QObject::connect() will fail if the connection already exists (i.e. if the same signal is already connected to the same slot for the same pair of objects). This flag was introduced in Qt 4.6.

在使用lambda连接信号槽的时候有一个注意点即

connect(this, &HousingAirLeakTest::Signal_TE_Logs_AppendText, [=](const QString &message) {
        QDateTime datatime = QDateTime::currentDateTime();
        QString time = datatime.toString("yyyy-MM-dd HH:mm:ss:zzz");
        if (ui.TE_Logs->document()->lineCount() > 3000)
        {
            ui.TE_Logs->clear();
        }
        ui.TE_Logs->append("[" + time + "] " + message);
    });

connect(this, &HousingAirLeakTest::Signal_TE_Logs_AppendText,this, [=](const QString &message) {
        QDateTime datatime = QDateTime::currentDateTime();
        QString time = datatime.toString("yyyy-MM-dd HH:mm:ss:zzz");
        if (ui.TE_Logs->document()->lineCount() > 3000)
        {
            ui.TE_Logs->clear();
        }
        ui.TE_Logs->append("[" + time + "] " + message);
    });

的连接方式是不同的
前者的连接方式Qt::DirectConnection而后者的连接方式Qt::AutoConnection,所以在多线程使用的时候要注意,保险使用添加槽的对象

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值