qt信号和槽函数
Qt是一个跨平台的C++框架,主要用来开发GUI界面程序,也可以用来开发没有界面的命令行程序。支持功能类似Virtual studio。但是和Virtual Studio不同的是,Qt支持运行在Linux,Window,Macos等桌面系统,甚至支持在Android,IOS等移动设备运行。我比较好奇的是Qt生成的windows程序,反编译后的的汇编入口标识和Virtualbox studio是否相同,有时间会试试看。

一、 信号和槽函数
在GUI编程过程中,当修改一个界面部件时,我们经常需要调整另一个部件的行为。比如下面登录界面。

当选择手动设置选项,那么下面对应的IP地址和端口等配置项要变为可用状态。也就是说当一个部件修改要通知下面的部件调整显示状态变为可用。使用MFC做界面开发的大佬应该比较熟悉事件和函数绑定。比如下面代码实现单击BTN1按钮调用OnBtnClick函数
1 | ON_BN_CLICKED(BTN1, OnBtnClick) |
但是,Qt并没有使用这种函数回调的方式进行函数和事件的绑定,而是采用信号和槽机制替换回调方式。信号和槽函数用于Qt对象之前的通信,是Qt核心特性。Qt中的部件(比如按钮,单选框,列表框)提供了很多预定义的信号和信号槽。信号是指Qt的界面部件被点击或选中等操作后出发的操作信息,比如上面网络代理设置界面选择手动设置选项后会触发**itemClicked**信号。信号槽是响应特定信号而调用的函数。Qt 的小部件有许多预定义的插槽。还是拿上面的列表举例(假如使用QListWidget实现),QListWidget包含如下槽函数
二、 连接信号和槽函数
Qt使用connect函数实现信号和槽函数的绑定,伪代码原型如下
1 | // Object1发出了signal1信号, Object2对象执行他的slot1槽函数 |
当然,一般来说使用匿名函数作为槽函数更加方便,也是通常的做法
1 | connect(Object1, signal1, [=](){ |
使用信号和信号槽机制的好处是,发出信号的部件无需知道发出信号的处理函数。同样,槽函数也无需知道处理的是哪个部件发出的信号。这种松散耦合的设计保证只需要使用connect
函数连接信号和槽函数,就可以保证一个信号的发生后对应的槽函数会被调用。并且信号和槽函数可以接受任意数量和任务类型的参数,并且完全是类型安全的。比如QLabel的槽函数setNum就是被重载的。

信号也是可以重载的,但是没有找到对应的widget组件,哪天遇到了再补个图
附:Qt5类文档 https://doc.qt.io/qt-5/classes.html
三、 示例:点击按钮获取文本框内容
开发环境如下
开发环境 | 版本 |
---|---|
系统版本 | linux mint 20.3, 内核版本5.4.0-107 |
ide | Qt Creator 4.14.2 |
编译器 | Qmake |
Qt版本 | 5.15.2 |

新建Qwidget项目
由于只是示例按钮点击获取文本内容,创建Qdialg足够用了。ui文件暂时也不用,用代码创建按钮和文本输入框。过程和代码如下:
代码实现增加按钮和文本输入框
Qt界面组件也是一个C++类,所以QDialg上的组件是在构造函数总添加并加载的,对话框关闭,也就是析构函数执行时释放资源。因此,只需要在Qdialog类的构造函数增加代码即可。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
this->setFixedSize(400, 300); // 对话框400x300,不可拉伸
QPushButton *btn = new QPushButton(this); // 新建按钮
btn->setText("按我打印文本框内容");
btn->setGeometry(QRect(150, 200, 150, 40));
QLineEdit *text = new QLineEdit(this);
text->setText("初始内容");
text->setGeometry(QRect(50, 50, 300, 50));
// 弹出消息框显示文本框内容
QMessageBox *messageBox = new QMessageBox(this);
// 按钮按下获取文本框内容并打印
connect(btn, &QPushButton::clicked, [=](){
// 打印日志
qDebug() << text->text();
messageBox->setText(text->text());
messageBox->show();
});
}
Dialog::~Dialog()
{
}
四、 自定义信号和槽函数
前面写过信号和槽用于Qt对象之间的通信,那么信号的定义应该是Qt对象树的最顶端的对象支撑的。事实确实也是如此,不管是QWidget还是QPushButton都是继承自QObject,这点可以类比到JAVA所有对象都继承自Object。新建一个类CustomSignalTest并继承自QObject

完成后打开头文件(customsignaltest.h),在signals块定义一个eat信号
1 |
|
基于上面按钮点击后弹出文本框内容的例子, 当点击按钮后,发出eat信息,文本框接受到eat信号后将文本框的字体颜色改为红色。正常情况下我们不会这么做,如此击鼓传花只为演示自定义信号的使用。还是在Dialog构造函数添加代码,最终代码如下
1 |
|

五、 信号重载
上面自定义信号是没有任何参数的,有些时候是需要发送信号的同时传入参数,这个时候就需要对信号进行重载,部分代码如下
1 | signals: |
当触发了带参数的重载方法后,将发送信号时传入的字符串打印出来。增加重载方法后会发现上面的例子报错了。原因是connect无法判断应该接收哪个eat信号,所以需要声明,修改后的部分代码如下
1 | // 当ct发出eat信号时,文本框变为红色 |
接收带参数的信号和无参数信号类似,首先发送信息位置增加参数
1 | // 按钮按下获取文本框内容并打印 |
接收带参数的信号,打印到终端
1 | // 定义带参数的信号变量 |

附:
qt类文档: https://doc.qt.io/qt-6/classes.html
qt资源下载地址: https://download.qt.io/