QT信号与槽——观察者模式——回调函数

QT信号与槽——观察者模式——回调函数

1、QT信号与槽机制

1.1信号本质

信号是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时候 Qt 对应的窗口类会发出某个信号。比如:信号的本质是事件

按钮单击、双击
窗口刷新
鼠标移动、鼠标按下、鼠标释放
键盘输入

在QT中信号的发出者是某个实例化的类对象,对象内部可以进行相关事件的检测。

1.2槽的本质

在 Qt 中槽函数是一类特殊的功能的函数,在编码过程中也可以作为类的普通成员函数来使用。之所以称之为槽函数是因为它们还有一个职责就是对 Qt 框架中产生的信号进行处理。

比如:和朋友一起玩游戏(csgo),朋友说:我要丢闪了,于是我背身一下防闪;

实例对象角色描述
朋友信号发出者信号携带的信息: 我要丢闪了
信号接收者处理朋友发射的信号: 背身

在Qt中槽函数的所有者也是某个类的实例对象。

1.3信号和槽关系

在 Qt 中信号和槽函数都是独立的个体,本身没有任何联系,但是由于某种特性需求我们可以将二者连接到一起,在 Qt 中我们需要使用 QOjbect类中的 connect 函数进二者的关联。

QMetaObject::Connection QObject::connect(
    	const QObject *sender, PointerToMemberFunction signal, 
        const QObject *receiver, PointerToMemberFunction method, 
		Qt::ConnectionType type = Qt::AutoConnection);
/*参数:
  - sender:   发出信号的对象
  - signal:   属于sender对象, 信号是一个函数, 这个参数的类型是函数
              指针, 信号函数地址
  - receiver: 信号接收者
  - method:   属于receiver对象, 当检测到sender发出了signal信号, 
              receiver对象调用method方法,信号发出之后的处理动作*/
 
//  参数 signal 和 method 都是函数地址, 因此简化之后的 connect() 如下:框架自动调用
connect(const QObject *sender, &QObject::signal, 
        const QObject *receiver, &QObject::method);

2、标准信号槽

QT自带的一些信号与槽函数

3、自定义信号槽

Qt 框架提供的信号槽在某些特定场景下是无法满足我们的项目需求的,因此我们还设计自己需要的的信号和槽,同样还是使用 connect () 对自定义的信号槽进行连接。

如果想要在QT类中自定义信号槽, 需要满足一些条件, 并且有些事项也需要注意:

注意
要编写新的类并且让其继承Qt的某些标准类
这个新的子类必须从QObject类或者是QObject子类进行派生
在定义类的头文件中加入 Q_OBJECT 宏不加无法使用QT的信号槽机制
// 在头文件派生类的时候,首先像下面那样引入Q_OBJECT宏:
class MyMainWindow : public QWidget
{
    Q_OBJECT
    ......
}
#ifndef MAINWINDOW_H 
#define MAINWINDOW_H 
  
#include <QMainWindow> 
/* 引入 QPushButton */ 
#include <QPushButton> 

class MainWindow : public QMainWindow 
{ 
  Q_OBJECT 
 
  public: 
      MainWindow(QWidget *parent = nullptr); 
      ~MainWindow(); 
 
  signals: 
      /* 声明一个信号,只需声明,无需定义 */ 
      void pushButtonTextChanged(); 
 }; 
 #endif // MAINWINDOW_H 

3.1自定义信号

信号是类的成员函数,返回值必须是 void 类型,信号的名字可以根据实际情况进行指定,参数可以随意指定, 信号也支持重载,信号需要使用 signals 关键字进行声明, 使用方法类似于public等关键字,信号函数只需要声明, 不需要定义(没有函数体实现),在程序中发射自定义信号: 发送信号的本质就是调用信号函数,习惯性在信号函数前加关键字: emit, 但是可以省略不写,emit只是显示的声明一下信号要被发射了, 没有特殊含义,底层 emit == #define emit

// 举例: 信号重载
// Qt中的类想要使用信号槽机制必须要从QObject类派生(直接或间接派生都可以)
class Test : public QObject
{
    Q_OBJECT
signals:
    void AA();
	// 参数的作用是数据传递, 谁调用信号函数谁就指定实参
	// 实参最终会被传递给槽函数
    void AA(int a);
};

3.2自定义槽

自定义槽注意事项
返回值必须是 void 类型
槽也是函数, 因此也支持重载
槽函数需要指定多少个参数, 需要看连接的信号的参数个数
槽函数的参数是用来接收信号传递的数据的, 信号传递的数据就是信号的参数
信号函数: void AA(int a, double b);
槽函数: void AA(int a, double b);
槽函数的参数应该和对应的信号的参数个数,从左到右类型依次对应
信号的参数可以大于等于槽函数的参数个数 == 信号传递的数据被忽略了
信号函数: void AA(int a, double b);
槽函数: void AA(int a);
Qt中槽函数的类型是多样的

Qt 中的槽函数可以是类的成员函数、全局函数、静态函数、Lambda表达式(匿名函数)
槽函数可以使用关键字进行声明: slots (Qt5中slots可以省略不写)

public slots:
private slots: –> 这样的槽函数不能在类外部被调用
protected slots: –> 这样的槽函数不能在类外部被调用。
// class A
class A : public QObject
{
    Q_OBJECT
public:
    explicit A(QObject *parent = nullptr);

signals:
    void sig();	            // 不能表达出想要吃什么
    void sig(QString msg);	// 可以通过参数表达想要吃什么
};

// class B
class B : public QObject
{
    Q_OBJECT
public:
    explicit B(QObject *parent = nullptr);

public slots:
    // 槽函数
    void slo();             // 不能知道信号发出者要吃什么
    void slo(QString msg);  // 可以知道信号发出者要吃什么
};

4、信号槽扩展

信号与槽可以多对一,也可以一对多

QT4连接方式

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

QT5及以上连接方式

connect(const QObject *sender, &QObject::signal, 
        const QObject *receiver, &QObject::method);

用QT5的连接方式时要注意槽函数重载问题,使用函数指针,比如:

// 定义函数指针指向重载的某一个具体的信号地址
void (Me::*mysignal)(QString) = &Me::eat;
// 定义函数指针指向重载的某一个具体的槽函数地址
void (Me::*myslot)(QString) = &Me::hungury;
// 使用定义的函数指针完成信号槽的连接
connect(&m, mysignal, &m, myslot);

最好使用QT5的连接方式,因为这样能检查出错误,QT4的使用宏定义把函数名变为字符串,即使写错了也不会报错;

参考:Qt开发编程-入门基础教程Qt5

【正点原子】 I.MX6U 嵌入式 Qt 开发指南 V1.0

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值