zoukankan      html  css  js  c++  java
  • Qt信号与槽的使用

    参考视频:黑马程序员https://www.bilibili.com/video/BV1XW411x7NU?p=4

    1  新建工程

    先创建一个控件基础工程,创建后的界面如下:

    主函数我们不需要修改,就保持这样,对于C++的知识我不太理解。

    上述代码中,执行到第7行的时候,会先去执行基类的构造函数,再执行MyWidget类的构造函数。我们只需要在构造函数中实现需要实现的功能。

    构造函数对应在mywidget.cpp中:

    2  测试代码

    实例一:标准的信号处理

    测试目的:在主窗口中,新建两个按钮,功能如下:

    按钮一的功能:按下按钮,关闭主窗口;

    按钮二的功能:释放按钮,更改按钮二的文本,并隐藏按钮一。

    由于在实现过程中,会用到信号与槽的知识,就先简单介绍一下基本知识,可能不正确,这只是我个人的理解:

    信号:某一事件发生时产生,用于表示一个事件发生了。

    槽:就是信号处理函数,用于指示当信号发生时,需要做出什么动作。

    其中,我们connect函数来连接信号与槽之间的关系,函数的原型如下:

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

    举例说明:

    connect(&b1, &QPushButton::pressed, this, &MyWidget::close);

    /* &b1:信号发出者,指针类型

    * &QPushButton::pressed:处理的信号,&发送者的类名::信号名字

    * this:信号接收者

    * &MyWidget::close:槽函数,信号处理函数 &接收的类名::槽函数名字

    */

    不同的控件有哪些信号,可通过帮助文档查看,以QPushButton为例进行说明(点QPushButton,再按F1):

    这里没有看到signal函数,可能是从它的父类继承过来的,我们再看一下它的父类:

     实现的相关代码

     先在MyWidget类中实现两个按钮(mywidget.h):

     1 #ifndef MYWIDGET_H
     2 #define MYWIDGET_H
     3 
     4 #include <QWidget>
     5 #include <QPushButton>
     6 
     7 class MyWidget : public QWidget
     8 {
     9     Q_OBJECT
    10 
    11 public:
    12     MyWidget(QWidget *parent = 0);
    13     ~MyWidget();
    14 
    15 private:
    16     QPushButton b1;
    17     QPushButton *b2;
    18 
    19     void myslot();
    20 
    21 };
    22 
    23 #endif // MYWIDGET_H
    View Code

    再在构造函数中实现两个按钮的功能(mywidget.cpp):

     1 #include "mywidget.h"
     2 #include <QPushButton>
     3 
     4 MyWidget::MyWidget(QWidget *parent)
     5     : QWidget(parent)
     6 {
     7     b1.setParent(this);
     8     b1.setText("按钮一");
     9     b1.move(100, 100);
    10 
    11     b2 = new QPushButton(this);
    12     b2->setText("按钮二");
    13 
    14     connect(&b1, &QPushButton::pressed, this, &MyWidget::close);
    15     /* &b1:信号发出者,指针类型
    16     *  &QPushButton::pressed:处理的信号,&发送者的类名::信号名字
    17     *  this:信号接收者
    18     *  &MyWidget::close:槽函数,信号处理函数 &接收的类名::槽函数名字
    19     */
    20 
    21     /*
    22      * 自定义槽,普通函数的用法
    23      * Qt5:任意的成员函数,普通全局函数,静态函数
    24      * 槽函数需要和信号一致(参数、返回值)
    25      * 由于信号都是没有返回值,所以槽函数一定没有返回值
    26      */
    27      connect(b2, &QPushButton::released, this, &MyWidget::myslot);
    28 
    29      connect(b2, &QPushButton::released, &b1, &MyWidget::hide);
    30     /*
    31      * 信号:短信
    32      * 槽函数:接收短信的手机
    33     */
    34 }
    35 
    36 void MyWidget::myslot()
    37 {
    38     b2->setText("123");
    39 }
    40 
    41 MyWidget::~MyWidget()
    42 {
    43 
    44 }
    View Code

    运行,进行测试:

     实例二:自定义不带参数信号处理

    目的:实现两个窗口,主窗口和子窗口,并且每个窗口都有一个按键,按键功能如下:

    主窗口按键的功能:显示子窗口,关闭父窗口;

    子窗口按键的功能:关闭子窗口,显示父窗口。

    主窗口和子窗口的切换显示全部由主窗口控制,可以理解为:主窗口的权限大于子窗口,子窗口的按键按下去只是产生一个信号,主窗口再对信号进行处理。

    新建一个工程,工程创建之后,有以下文件,其中,subwindown相关文件是通过点击signal_slot_2目录文件,选择添加新文件,选择C++ --> C++ Class,基类我们选择QWidget:

     实现的代码如下:

    widget.h是widget类所在同文件,主要实现:声明主窗口按键处理函数、声明子窗口信号接收处理函数、实例化一个subwindown类对象、实例化一个QPushButton类对象。

     1 #ifndef WIDGET_H
     2 #define WIDGET_H
     3 
     4 #include <QWidget>
     5 #include <QPushButton>
     6 #include "subwindown.h"
     7 
     8 class Widget : public QWidget
     9 {
    10     Q_OBJECT
    11 
    12 public:
    13     Widget(QWidget *parent = 0);
    14     ~Widget();
    15 
    16     void my_slot();
    17     void dealsub();
    18 
    19 private:
    20     QPushButton b_main;
    21 
    22     subwindown sw;
    23 };
    24 
    25 #endif // WIDGET_H
    View Code

    subwindown.h是subwindown类所在头文件,主要实现:声明子窗口按键处理函数、声明一个信号、实例化一个QPushButton类对象。

     1 #ifndef SUBWINDOWN_H
     2 #define SUBWINDOWN_H
     3 
     4 #include <QWidget>
     5 #include <QPushButton>
     6 
     7 class subwindown : public QWidget
     8 {
     9     Q_OBJECT
    10 public:
    11     explicit subwindown(QWidget *parent = nullptr);
    12     //定义槽函数
    13     void sendslot();
    14 
    15 signals:
    16     /*
    17     * 信号必须有signals关键字声明
    18     * 信号没有返回值,但可以有参数
    19     * 信号就是函数的声明,只需声明,无需定义
    20     * 使用:emit mysignal();
    21     */
    22     void mysignal();
    23 
    24 public slots:
    25 
    26 private:
    27     QPushButton b_sub;
    28 
    29 };
    30 
    31 #endif // SUBWINDOWN_H
    View Code

    main.cpp中的代码不改动,就使用生成的代码:

     1 #include "widget.h"
     2 #include <QApplication>
     3 
     4 int main(int argc, char *argv[])
     5 {
     6     QApplication a(argc, argv);
     7     Widget w;
     8     w.show();
     9 
    10     return a.exec();
    11 }
    View Code

    widget.cpp中实现的是主窗口的构造函数,主要实现:接收主窗口按键的信号并处理、接收子窗口发送的信号并处理。

     1 #include "widget.h"
     2 
     3 Widget::Widget(QWidget *parent)
     4     : QWidget(parent)
     5 {
     6     setWindowTitle("主窗口");
     7 
     8     //设置按钮相关属性
     9     b_main.setParent(this);
    10     b_main.setText("切换子窗口");
    11     b_main.move(50, 50);
    12     //处理主窗口的按钮所产生的信号
    13     connect(&b_main, &QPushButton::clicked, this, Widget::my_slot);
    14 
    15     //接收子窗口信号,并进行处理
    16     connect(&sw, &subwindown::mysignal, this, &Widget::dealsub);
    17     resize(400, 300);
    18 }
    19 
    20 void Widget::my_slot()
    21 {
    22     //显示子窗口
    23     sw.show();
    24     //父窗口隐藏
    25     this->hide();
    26 }
    27 
    28 void Widget::dealsub()
    29 {
    30     //主窗口显示
    31     this->show();
    32     //子窗口隐藏
    33     sw.hide();
    34 }
    35 
    36 Widget::~Widget()
    37 {
    38 
    39 }
    View Code

    subwindown.cpp中实现的是子窗口的构造函数,主要实现:接收子进程按键的信号并处理,处理方式为发送一个自定义信号。

     1 #include "subwindown.h"
     2 
     3 subwindown::subwindown(QWidget *parent) : QWidget(parent)
     4 {
     5     setWindowTitle("子窗口");
     6 
     7     //按键属性设置
     8     b_sub.setText("切换主窗口");
     9     b_sub.setParent(this);
    10     b_sub.move(50, 50);
    11 
    12     //接收按键信号并处理
    13     connect(&b_sub, &QPushButton::clicked, this, &subwindown::sendslot);
    14     resize(400, 300);
    15 }
    16 
    17 void subwindown::sendslot()
    18 {
    19     //发送信号
    20     emit mysignal();
    21 }
    View Code

    运行测试:

    点击“切换子窗口”按键:

    实例三:自定义带参数信号处理

    功能:在空白窗口中定义一个按钮,点击按钮发送一个自定义的带参数的信号,然后由本窗口接收信号并将参数打印出来。

    首先,创建一个控件基类工程,创建后包含的文件如下:

    在widget.h中,实现的功能有:声明一个发送信号函数、声明一个接收信号函数、自定义一个带参数的信号、实例化一个QPushButton对象。

     1 #ifndef WIDGET_H
     2 #define WIDGET_H
     3 
     4 #include <QWidget>
     5 #include <QPushButton>
     6 
     7 class Widget : public QWidget
     8 {
     9     Q_OBJECT
    10 
    11 public:
    12     Widget(QWidget *parent = 0);
    13     ~Widget();
    14 
    15     //点击按钮,发送信号函数
    16     void send_signal();
    17     //接收信号处理函数
    18     void recv_signal(int, QString);
    19 
    20 signals:
    21     //自定义一个带参数的信号
    22     void mysignal(int, QString);
    23 
    24 private:
    25     QPushButton b_main;
    26 
    27 };
    28 
    29 #endif // WIDGET_H
    View Code

    在widget.cpp中,实现的功能有:接收点击按键的信号并进行处理,接收自定义的信号并进行处理。

     1 #include "widget.h"
     2 #include <QDebug>
     3 
     4 Widget::Widget(QWidget *parent)
     5     : QWidget(parent)
     6 {
     7     b_main.setParent(this);
     8     b_main.setText("发送");
     9     b_main.move(100, 100);
    10 
    11     //点击按钮,发送信号
    12     connect(&b_main, &QPushButton::clicked, this, &Widget::send_signal);
    13 
    14     //接收点击按钮,发送的信号
    15     void (Widget::*testsignal)(int, QString) = &Widget::mysignal;
    16     connect(this, testsignal, this, &Widget::recv_signal);
    17 
    18     this->resize(300, 300);
    19 }
    20 
    21 void Widget::send_signal()
    22 {
    23     emit mysignal(100, "我已经发送信号");
    24 }
    25 
    26 void Widget::recv_signal(int a, QString str)
    27 {
    28     qDebug() << a << str;
    29 }
    30 
    31 Widget::~Widget()
    32 {
    33 
    34 }
    View Code

    运行,并进行测试,点击一次发送按钮,就会发送一个自定义信号,并接收到了它:

    实例四:lambda表达式的使用 

    功能:创建一个按钮,点击按钮发送一个信号,不需要指定信号接收函数和信号接收者,直接使用匿名函数(lambda表达式)实现。

    先新建一个工程,新建后的工程文件如下:

    由于lambda是C++11支持的特性,所以我们需要在lambda_test.pro文件末尾添加一句:CONFIG += C++11

    先把代码放上,再说明lambda表达式的作用。

    widget.h文件:

     1 #ifndef WIDGET_H
     2 #define WIDGET_H
     3 
     4 #include <QWidget>
     5 #include <QPushButton>
     6 
     7 class Widget : public QWidget
     8 {
     9     Q_OBJECT
    10 
    11 public:
    12     Widget(QWidget *parent = 0);
    13     ~Widget();
    14 
    15 private:
    16     //定义一个类中成员变量
    17     int a = 10;
    18 
    19 };
    20 
    21 #endif // WIDGET_H
    View Code

    widget.cpp文件:

     1 #include "widget.h"
     2 #include <QDebug>
     3 
     4 Widget::Widget(QWidget *parent)
     5     : QWidget(parent)
     6 {
     7     QPushButton *b_main = new QPushButton(this);
     8     b_main->setParent(this);
     9     b_main->setText("开始");
    10     b_main->move(100, 100);
    11 
    12     //定义一个外部局部变量
    13     int b = 12;
    14     //Lambda表达式,匿名函数对象
    15     //C++11增加的新特性,项目文件: CONFIG += C++11
    16     //Qt配合信号一起使用,非常方便
    17     connect(b_main, &QPushButton::clicked,
    18         // =:把外部所有局部变量、类中所有成员以值方式传进来
    19         // this:类中所有成员以值传递方式
    20         // &:引用符号,外部所有局部变量
    21         [=](bool isCheck)mutable
    22         {
    23             b_main->setText("lambda表达式");
    24             qDebug() << "已经进入lambda表达式";
    25             qDebug() << a << b;
    26             a += 10;
    27             b += 20;
    28             qDebug() << isCheck;
    29         }
    30     );
    31 
    32     this->resize(300, 300);
    33 }
    34 
    35 Widget::~Widget()
    36 {
    37 
    38 }
    View Code

    下面就简单的说明lambda表达式的语法,我也不是很懂,根据测试结果进行说明。

    参考了这篇博客:https://www.cnblogs.com/rainbow70626/p/10328143.html

    格式:[capture](parameters) mutable ->return-type{statement};

    capture:捕捉列表,也单独代表函数的开始,主要有以下使用方式:

    • 单独传递外部变量,如:[b_main]
    • =:把外部所有局部变量、类中所有成员以值方式传进来(widget.c和widget.h文件中的成员)
    • this:类中所有成员以值传递方式(widget.h文件中的成员)
    • &:引用符号,外部所有局部变量(widget.c文件中的成员),当变量是指针时,最好别用这个。

    parameters:参数列表,信号的参数。

    mutable :值传递时,默认变量为只读的,如果需要在匿名函数中改变它,需要这个参数

    运行代码进行测试:

  • 相关阅读:
    旧文备份:CANopen协议PDO的几种传输方式
    CANopen 基础
    单片机FLASH与RAM、ROM的关系
    在CANopen网络中通过LSS服务设置节点地址和网络波特率
    STM32F103 CAN中断发送功能的再次讨论
    由RS-232串口到PROFIBUS-DP总线的转换接口设计
    profibus 的DPV0 和DPV1
    PROFIBUS-DP
    profibus总线和profibus dp的区别
    获取验证码倒计时
  • 原文地址:https://www.cnblogs.com/mrlayfolk/p/13124400.html
Copyright © 2011-2022 走看看