Qt 信号与槽

Qt 信号与槽

文章目录

  • Qt 信号与槽
    • 信号与槽的概念
      • Qt的信号与槽机制概述
      • **信号函数**
        • 信号的定义
        • 信号的发射
      • **槽函数**
      • 槽函数与信号函数的连接
        • 1、使用Qt设计师
        • 2、使用 `QObject::connect()`
    • Qt预定义的信号与槽

参考:【Qt】一篇全面的信号和槽函数机制总结_iriczhao的博客-CSDN博客_qt 信号和槽的机制

信号与槽的概念

Qt的信号与槽机制概述

信号和槽机制是Qt的核心特性,用于多个对象之间的通信。Qt的元对象系统是信号和槽实现的基础。

特点:

  1. 信号和槽机制是类型安全的:信号的参数必须与接收槽函数的参数相匹配。(实际上,槽的参数可以比它接收到的信号参数更少,因为槽可以忽略额外的参数)
  2. 信号和槽函数是松耦合的:当一个对象发出信号,该对象不知道也不关心哪个对象的槽函数会接收该信号。Qt的信号和槽函数机制确保:如果将一个信号连接到一个槽函数上,该槽函数将在正确的时间被调用。
  3. 可以将多个信号连接到一个槽函数上(即【多对一】),而一个信号也可以连接到多个槽函数上【即一对多】

信号函数

  • 可以重载
  • 定义在某个类中,该类直接或间接继承自 QObject 类,且添加 Q_OBJECT
  • signals 关键字修饰;
  • 函数只需要声明,不需要定义(实现),实现是由QT的moc工具自动完成的;
  • 函数的返回值类型必须为 void,参数的类型和个数不限。

在Qt框架下,信号发出分为两种:

  1. 【每个类预定义的信号】:这些信号何时发出可以通过查看官方文档获知。

  2. 【自定义的信号】:这些信号的发出由开发人员自行定义。

在此讲解自定义信号。

信号的定义

示例:

class MyWidget:public QWidget{
    //Q_OBJECT 是一个宏,添加它才能正常使用 Qt 的信号和槽机制
    Q_OBJECT
//信号函数
signals:
    //自定义的信号函数
    void MySignal(QString message);
};

信号的发射

信号可以从任何地方发出,但是建议:【只从定义该信号的类及其子类发出信号】

对于 Qt 提供给我们的信号函数,其底层已经设置好了信号发出的时机,例如按下鼠标时、点击 Enter 回车键时等等。

对于自定义的信号,我们需要自己指定信号发出的时机,需要使用 emit 关键字,专门用来发射信号。

可以在任何地方emit发射信号,不一定要在信号函数的函数体内。

用法是在自定义信号函数的函数体内使用 emit 关键字发射信号,格式如下:

emit 自定义信号函数(自定义信号函数的实参列表);

示例:

class MyWidget:public QWidget{
    //Q_OBJECT 是一个宏,添加它才能正常使用 Qt 的信号和槽机制
    Q_OBJECT
//信号函数
signals:
    void MySignal(QString mess);
public:
    void emitSignal(){
        emit MySignal(message);//使用emit发射信号
    }
private:
    QString message;
};

注意

emit语句之后的代码将在所有槽函数都返回之后才执行。如果使用排队连接,情况略有不同,在这种情况下,emit关键字后面的代码将立即继续,槽函数将稍后执行。

槽函数

槽函数是普通的C++成员函数,当一个连接到槽函数的信号被发射时,槽函数将被调用;由于槽是普通的成员函数,所以它们在直接调用时遵循普通的C++规则。但是作为槽函数时,任何组件都可以通过信号连接从而调用它们。

  • 可以重载
  • 可以使用slot关键字声明槽函数,Qt5之后可以不用
  • 信号可以与它们相连接
  • 需要手动实现
  • 返回值必须与所要响应的信号函数相同
  • 参数顺序必须与信号函数相同
  • 参数可以从后往前减少,当然也可以减少到没有参数【即参数个数小于等于信号函数的参数】

示例:

class MyWidget:public QWidget{
    //Q_OBJECT 是一个宏,添加它才能正常使用 Qt 的信号和槽机制
    Q_OBJECT
//信号函数
signals:
    //自定义的信号函数
    void MySignal(QString message);
//槽函数
public slots:
    void recSlot2(QString mess1,QString mess2){
        qDebug() << "执行 recSlot2() 槽函数,输出"<< mess1 << " " << mess2;
    }
};

槽函数与信号函数的连接

1、使用Qt设计师

详见:Qt 默认静态槽函数 connectSlotsByName浅析_3的4次方的博客-CSDN博客

2、使用 QObject::connect()

函数原型:

//connect(信号的发送者,信号的具体信息,信号的接受者,信号的处理[槽])
[static] QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)

(1)第一种方法:使用QObject::connect()以及信号和槽声明宏。

在Qt 4中,使用 SIGNAL() 宏声明信号,SLOT() 宏声明槽。

SIGNAL()SLOT()宏中包含参数的规则是:传递给SIGNAL()宏的参数不能少于传递给SLOT()宏的参数。

优点:信号和槽参数很直观

缺点:使用宏,编译时不做类型检查,只能在运行时发现错误

以下合法:

connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(Qbject*)));
connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed()));
connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed()));

以下不合法:

connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed(QObject*)));

(2)第二种方法:使用C++11的lambda函数

connect(sender, &QObject::destroyed, this, [=](){ this->m_objects.remove(sender); });

在这两种情况下,我们在connect()调用中提供这个上下文。上下文对象提供关于应该在哪个线程中执行接收器的信息。

当发送方或上下文被销毁时,lambda将断开连接。注意:当信号发出时,函数内部使用的所有对象依然是激活的。

优点:代码简洁

(3)第三种方法:使用函数指针。

在Qt 5中,可以使用函数指针取代宏。

connect(sender, &QObject::destroyed, this, &MyObject::objectDestroyed);

优点:允许编译器检查信号的参数是否与槽的参数兼容。如果需要,编译器还可以隐式地转换参数

缺点:无法识别函数重载的情况

Qt预定义的信号与槽

在对应的控件的Qt助手文档中的 Signal Documentation 栏下面有罗列

你可能感兴趣的:(Qt,qt,开发语言)