【Qt】8.信号和槽_自定义信号和槽
文章目录
- 1. 自定义信号和槽
- 1.1 基本语法
- 1.2实例
- 1.3 带参数的信号和槽
1. 自定义信号和槽
1.1 基本语法
Qt
中也允许自定义信号:自定义槽函数,非常关键,开发中大部分情况都是需要自定义槽函数的槽函数,就是用户触发某个操作之后,要进行的业务逻辑
自定义信号,比较少见,实际开发中很少会需要自定义信号。
信号就对应到用户的某个操作。在
GUI
,用户能够进行哪些操作,是可以穷举的。
Qt
内置的信号,基本上已经覆盖到了上述所有可能的用户操作。因此,使用Qt
内置的信号,就足以应付大部分的开发场景了。自定义信号,本身代码比较简单的。
1、自定义信号函数书写规范
- 自定义信号函数必须写到 “
signals
” 下;- 返回值为
void
,只需要声明,不需要实现;- 可以有参数,也可以发生重载;
2、自定义槽函数书写规范
- 早期的
Qt
版本要求槽函数必须写到 “public slots
” 下,但是现在高级版本的Qt
允许写到类的- “
public
” 作用域中或者全局下;返回值为void
,需要声明,也需要实现;- 可以有参数,可以发生重载;
3、发送信号
使用 “
emit
” 关键字发送信号 。“emit
” 是一个空的宏。“emit
” 其实是可选的,没有什么含义,只是为了提醒开发人员。
咱们的
Widget
虽然还没有定义任何信号,由于继承自QWidget
,和QObject
,这俩类里面已经提供了一些信号了,可以直接使用。所谓的
Qt
的信号,本质上也就是一个“函数”。
Qt5
以及更高版本中,槽函数和普通的成员函数之间,没啥差别了。
但是,信号,则是一类非常特殊的函数。
程序员只要写出函数声明,并且告诉
Qt
,这是一个“信号”即可。这个函数的定义,是
Qt
在编译过程中,自动生成的。(自动生成的过程,程序员无法干预)信号在Qt中是特殊的机制。Qt生成的信号函数的实现,要配合Qt框架做很多既定的操作。
作为信号函数,这个函数的返回值,必须是
void
。
有没有参数都可以,甚至也可以支持重载。
signals:
这个也是Qt
自己扩展出来的关键字,qmake
的时候,调用一些代码的分析/生成工具。
扫描到类中包含signals
这个关键字的时候,此时,就会自动的把下面的函数声明
认为是信号,并且给这些信号函数自动的生成函数定义。
1.2实例
widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();signals:void mySignal();public:void handleMySignal();private:Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);connect(this,&Widget::mySignal,this,&Widget::handleMySignal);
}Widget::~Widget()
{delete ui;
}void Widget::handleMySignal()
{this->setWindowTitle("处理自定义信号");
}
运行后:
为啥呢?因为只建立了连接,没有发送信号。
connect(this,&Widget::mySignal,this,&Widget::handleMySignal);
建立连接,不代表信号发出来了。
如何才能触发出自定义的信号呢?
Qt
内置的信号,都不需要咱们手动通过代码来触发。用户在
GUI
,进行某些操作,就会自动触发对应信号。(发射信号的代码已经内置到Qt
框架中了)
Qt
提供了一个关键字:emit
(发射)通过
emit mySignal();
就可以触发对应的信号。
也不一定要在构造函数里面搞,弄到按钮里面就是点击按钮,发送自定义操作。
使用过程:
点击按钮--->QPushButton:clicked--->Widget::on_pushButton_clicked()--->emit mySignal();--->void Widget::handleMySignal()
其实在
Qt 5
中emit
现在啥都没做。真正的操作都包含在mySignal
内部生成的函数定义了即使不写
emit
,信号也能发出去。刚刚的:
void Widget::on_pushButton_clicked()
里面不写emit
,也可以发送即使如此,实际开发中,还是建议把
emit
都加上。加上代码可读性更高,更明显的标识出,这里是发射自定义的信号了。当然内置的信号也可以发送。
1.3 带参数的信号和槽
Qt
的信号和槽也支持带有参数, 同时也可以支持重载。此处我们要求, 信号函数的参数列表要和对应连接的槽函数参数列表一致。
此时信号触发, 调用到槽函数的时候, 信号函数中的实参就能够被传递到槽函数的形参当中。
通过这样的机制, 就可以让信号给槽传递数据了。
signals:void mySignal(const QString&);public:void handleMySignal(const QString&);
这里的参数必须要一致。
一致主要是要求类型,个数如果不一致也可以。
不一致的时候,要求信号的参数的个数必须要比槽的参数个数要更多。
C++中声明函数的时候,形参的名字可以不必写。
text
也就是带参数的信号
。
运行:
点击:
传参可以起到复用代码的效果。
有多个逻辑,逻辑上整体一致,但是涉及到的数据不同,就可以通过函数-参数来复用代码,并且在不同的场景中传入不同的参数即可
signals:void mySignal(const QString& text);public:void handleMySignal(const QString& text);
改完后,运行:
点击按钮1:
点击按钮2:
通过这一套信号槽,搭配不同的参数,就可以起到设置不同标题的效果。
connect(this,&Widget::mySignal,this,&Widget::handleMySignal);
Qt
中很多内置的信号,也是带有参数的。(这些参数不是咱们自己传递的)
clicked
信号就带有一个参数,bool
。这个参数表示当前按钮是否处于“选中”状态。
这个选中状态对于
QPushButton
没啥意义,对于QCheckBox
复选框,就很有用了。
然后给信号函数加个参数
signals:void mySignal(const QString& text,const QString& text2);public:void handleMySignal(const QString& text);
但是反过来就不行
直观的思考,应该是要求信号的参数个数和槽的参数个数,严格一致,此处为啥允许信号的参数比槽的参数多呢??
一个槽函数,有可能会绑定多个信号。
如果我们严格要求参数个数一致,就意味着信号绑定到槽的要求就变高了。
换而言之,当下这样的规则,就允许信号和槽之间的绑定更灵活了,更多的信号可以绑定到这个槽函数上了。
个数不一致,槽函数就会按照参数顺序,拿到信号的前
N
个参数。至少需要确保,槽函数的每个参数都是有值的。
然后我们来改一下代码:
可以看到编译报错的,因为带有参数的信号,要求信号的参数和槽的参数要一致
类型,个数
要满足要求(信号的参数个数要多于槽的参数个数)
展开的代码还可以展开,最终展开的效果会得到一系列很复杂的代码
这些代码就涉及到Qt实现的内部原理了。(此处就不去深入研究了)
如果不加这个宏,这个类在编译的时候也会出错!