• Qt 信号和槽


    目录

    概念

    代码

    mainwindow.h

    me.h

    xiaohuang.h

    main.cc

    mainwindow.cc

    me.cc

    xianghuang.cc

    mainwindow.ui

    自定义信号的要求和注意事项:

    自定义槽的要求和注意事项:


    概念

    信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式(发布-订阅模式)。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。

    信号 的本质就是事件

    信号的呈现形式就是函数, 也就是说某个事件产生了, Qt框架就会调用某个对应的信号函数, 通知使用者。

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

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

    代码

    mainwindow.h

    1. #ifndef MAINWINDOW_H
    2. #define MAINWINDOW_H
    3. #include
    4. #include "me.h"
    5. #include "xiaohuang.h"
    6. QT_BEGIN_NAMESPACE
    7. namespace Ui { class MainWindow; }
    8. QT_END_NAMESPACE
    9. class MainWindow : public QMainWindow
    10. {
    11. Q_OBJECT
    12. public:
    13. MainWindow(QWidget *parent = nullptr);
    14. ~MainWindow();
    15. //添加HungryBtn的槽函数
    16. void HungrySlot();
    17. private:
    18. Ui::MainWindow *ui;
    19. Me* _me;
    20. Xiaohuang* _xh;
    21. };
    22. #endif // MAINWINDOW_H

    me.h

    1. #ifndef ME_H
    2. #define ME_H
    3. #include
    4. class Me : public QObject
    5. {
    6. Q_OBJECT
    7. public:
    8. explicit Me(QObject *parent = nullptr);
    9. public slots:
    10. void eat();
    11. void eat(QString msg);
    12. };
    13. #endif // ME_H

    xiaohuang.h

    1. #ifndef XIAOHUANG_H
    2. #define XIAOHUANG_H
    3. #include
    4. class Xiaohuang : public QObject
    5. {
    6. Q_OBJECT
    7. public:
    8. explicit Xiaohuang(QObject *parent = nullptr);
    9. signals:
    10. void hungry();
    11. void hungry(QString msg);
    12. };
    13. #endif // XIAOHUANG_H

    main.cc

    1. #include "mainwindow.h"
    2. #include
    3. int main(int argc, char *argv[])
    4. {
    5. QApplication a(argc, argv);
    6. MainWindow w;
    7. w.show();
    8. return a.exec();
    9. }

    mainwindow.cc

    1. #include "mainwindow.h"
    2. #include "ui_mainwindow.h"
    3. MainWindow::MainWindow(QWidget *parent)
    4. : QMainWindow(parent)
    5. , ui(new Ui::MainWindow)
    6. {
    7. ui->setupUi(this);
    8. //方法一:标准信号和槽函数
    9. connect(ui->closeBtn,&QPushButton::clicked,this,&MainWindow::close);
    10. //方法二:自定义信号和槽函数
    11. _me = new Me;
    12. _xh = new Xiaohuang;
    13. //因为自定义的信号不能让qt框架去发送,所以我们用qt框架有的信号关联我们的自定义信号
    14. //间接去让他发送我们的自定义信号
    15. //a 这个是信号连接槽函数去间接发送信号
    16. //connect(ui->HungryBtn,&QPushButton::clicked,this,&MainWindow::HungrySlot);
    17. //b 现在我们信号连接信号
    18. //connect(ui->HungryBtn,&QPushButton::clicked,_xh,&Xiaohuang::hungry);
    19. //connect(_xh,&Xiaohuang::hungry,_me,&Me::eat);
    20. //但是对于带参的,Qt5这么写就有问题,因为重载了,所以编译器就不知道选带参还是不带的,所以有语法错误
    21. //我们就可以在外部定义一个函数指针来说明是带参的还是不带参的
    22. //void (Xiaohuang::* Xh1)() = &Xiaohuang::hungry;
    23. void (Xiaohuang::* Xh2)(QString) = &Xiaohuang::hungry;
    24. void (Me::* myp)(QString) = &Me::eat;
    25. //对于有传参的写法
    26. connect(_xh,Xh2,_me,myp);
    27. connect(_xh,Xh2,_me,myp);
    28. //我们上面是Qt5的信号和槽处理方式,现在我们来看Qt4的
    29. connect(_xh,SIGNAL(hungry()),_me,SLOT(eat()));
    30. //对于有传参的写法
    31. connect(_xh,SIGNAL(hungry(QString)),_me,SLOT(eat(QString)));
    32. connect(ui->HungryBtn,&QPushButton::clicked,this,&MainWindow::HungrySlot);
    33. //推荐使用Qt5,因为Qt4是宏替换,没有安全检查
    34. }
    35. MainWindow::~MainWindow()
    36. {
    37. delete ui;
    38. }
    39. void MainWindow::HungrySlot()
    40. {
    41. //按下按钮,发送自定义信号
    42. emit _xh->hungry();
    43. emit _xh->hungry("海鲜");
    44. }

    me.cc

    1. #include "me.h"
    2. #include
    3. Me::Me(QObject *parent) : QObject(parent)
    4. {
    5. }
    6. void Me::eat()
    7. {
    8. qDebug()<<"我带你去吃饭";
    9. }
    10. void Me::eat(QString msg)
    11. {
    12. qDebug()<<"我带你去吃:"<
    13. }

    xianghuang.cc

    1. #include "xiaohuang.h"
    2. Xiaohuang::Xiaohuang(QObject *parent) : QObject(parent)
    3. {
    4. }

    mainwindow.ui

    自定义信号的要求和注意事项:

    1. 信号是类的成员函数
    2. 返回值必须是 void 类型
    3. 信号的名字可以根据实际情况进行指定
    4. 参数可以随意指定, 信号也支持重载
    5. 信号需要使用 signals 关键字进行声明, 使用方法类似于public等关键字
    6. 信号函数只需要声明, 不需要定义(没有函数体实现)
    7. 在程序中发射自定义信号: 发送信号的本质就是调用信号函数
      • 习惯性在信号函数前加关键字: emit, 但是可以省略不写
      • emit只是显示的声明一下信号要被发射了, 没有特殊含义
      • 底层 emit == #define emit
    1. // 举例: 信号重载
    2. // Qt中的类想要使用信号槽机制必须要从QObject类派生(直接或间接派生都可以)
    3. class Test : public QObject
    4. {
    5. Q_OBJECT
    6. signals:
    7. void testsignal();
    8. // 参数的作用是数据传递, 谁调用信号函数谁就指定实参
    9. // 实参最终会被传递给槽函数
    10. void testsignal(int a);
    11. };

    自定义槽的要求和注意事项:

    1. 返回值必须是 void 类型

    2. 槽也是函数, 因此也支持重载

    3. 槽函数需要指定多少个参数, 需要看连接的信号的参数个数

    4. 槽函数的参数是用来接收信号传递的数据的, 信号传递的数据就是信号的参数

      • 举例:
        • 信号函数: void testsig(int a, double b);
        • 槽函数: void testslot(int a, double b);
      • 总结:
        • 槽函数的参数应该和对应的信号的参数个数, 从左到右类型依次对应
        • 信号的参数可以大于等于槽函数的参数个数 == 信号传递的数据被忽略了
          • 信号函数: void testsig(int a, double b);
          • 槽函数: void testslot(int a);
    5. Qt中槽函数的类型是多样的

      Qt中的槽函数可以是类的成员函数全局函数静态函数Lambda表达式(匿名函数)

    6. 槽函数可以使用关键字进行声明: slots (Qt5中slots可以省略不写)

      • public slots:
      • private slots: –> 这样的槽函数不能在类外部被调用
      • protected slots: –> 这样的槽函数不能在类外部被调用
    1. // 槽函数书写格式举例
    2. // 类中的这三个函数都可以作为槽函数来使用
    3. class Test : public QObject
    4. {
    5. public:
    6. void testSlot();
    7. static void testFunc();
    8. public slots:
    9. void testSlot(int id);
    10. };
  • 相关阅读:
    【算法-动态规划】最长公共子序列
    安卓逆向之抽象函数public abstract的hook定位处理
    Vscoe设置if __name__ == ‘__main__‘: 自动提示
    各位大佬,有什么办法能过滤掉箭头所示的标签呢
    Java多线程之Thread和Runnable多线程的简单实现(适合小白入门,十分简单)
    使用VSCODE链接Anaconda
    java-php-python-律师事务所网站计算机毕业设计
    Linux ln命令:建立链接文件
    服务器部署Oracle,并实现客户端远程连接
    Vue中设置背景图片和透明度
  • 原文地址:https://blog.csdn.net/weixin_62700590/article/details/134533630