前言
上个学期由于需要做一个期末大作业,于是决定使用Qt写一个学生管理系统,如图。在做这个项目的过程中,对于Qt的信号与槽有了更为深刻的认识(如对本人此项目有想法,可与我联系)。
本文不涉及较深的Qt底层实现,仅谈谈我个人的理解。
文章目录
提示:以下是本篇文章正文内容,下面案例可供参考
一、什么是信号与槽
1.打电话
我们知道,现实生活中,每个人几乎每时每刻都在接收信息,处理事件。
举个打电话的例子,
当来电话时,“来电话了”就是一个事件,
也就是说,“来电话了”这个事件发生了,
而你听到了“电话铃声”,这个“电话铃声”就相当于一个信号,
于是你“接听”了它,
这就意味着你接收了“电话声”这个信号,处理了它并作出回应,回应的方式就是“接听”。
2.将打电话这一系列动作放到Qt程序当中应该是怎样的
我们再回味回味,将这一系列动作放到Qt程序当中应该是怎样的:Qt的事件监听就相当于人的大脑在接收生活中的信息。
电话响了本身讲就是一个事件,那么我们如何得知事件已经发生呢?当然是通过电话发出的电话铃声了。
而这个电话铃声就是Qt发出的信号,我们就可以通过connect函数亦或是直接使用事件监听器去获取到这个信号(本文仅讨论connect函数的情况),然后通过槽函数,我们就可以处理这些信号,做一些文章。
普通信号的传递
二、信号、槽
普通的信号与槽
QPushButton* btn = new QPushButton("按钮1", this);
connect(btn,&QPushButton::clicked,[](){
//CODEBLOCKS
});
当然,如果你查阅了Qt助手会发现,QPushButton继承于QAbstractButton类,而QAbstractButton类中有一个clicked信号:
void clicked(bool checked = false)
会发现它携带了一个参数,那么上面的代码中匿名槽函数怎么没有携带参数呢?难道信号与槽的参数不是一一对应的吗?
当然是一一对应的,只不过由于这个信号携带了默认值,所以这种情况下槽函数可以的参数可以省略。
自定义信号与槽
准备工作
首先我们先定义一个MainWindow窗口(由于我是在Visual Studio2019中编写的代码,所以部分头文件于Qt自身有些不一样,但不影响学习)
请允许我先抛出实现的代码,然后听我娓娓道来。
SignalAndSlot.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_SignalAndSlot.h"
#include <qpushbutton.h>
#include <qtextedit.h>
class SignalAndSlot : public QMainWindow
{
Q_OBJECT
public:
SignalAndSlot(QWidget *parent = Q_NULLPTR);
QPushButton* btn;//举例用的按钮组件
QTextEdit* editText;//文本编辑框
void init();//初始化组件函数
void sendMySignal();//中间人
void getEditTextContent(QString text);//接收文本消息的槽函数
private:
Ui::SignalAndSlotClass ui;
signals:
void mySignal(QString msg);//自定义信号
};
在上述头文件中,btn与editText为我们的示例组件,init函数用于分配组件的内存、简单布局以及信号与槽函数的绑定。
头文件成员变量说明
成员变量 | 用途 | |
---|---|---|
pubilc | btn | 按钮示例组件 |
pubilc | editText | 文本编辑框示例组件 |
pubilc | void init() | 分配组件的内存、简单布局以及信号与槽函数的绑定。 |
pubilc | void sendMySignal() | 将绑定于按钮的clicked信号的槽函数,当触发clicked信号时,发送mySignal信号 |
pubilc | void getEditTextContent(QString text) | 将绑定于mySigal信号的槽函数,当触发mySignal信号时,获取到文本键框的文本消息 |
private | ui | Qt的ui类,用于绘制界面,本文不涉及 |
signals | void mySignal(QString msg) | 自定义信号 |
SignalAndSlot.cpp
#include "SignalAndSlot.h"
#include <qmessagebox.h>
#pragma execution_character_set("utf-8")
SignalAndSlot::SignalAndSlot(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
init();
}
/*初始化界面及事件绑定*/
void SignalAndSlot::init()
{
btn = new QPushButton("按钮1", this);//一个按钮
btn->move(200, 0);
editText = new QTextEdit(this);//一个文本编辑框
editText->resize(200, editText->size().height());
connect(btn, &QPushButton::clicked, this, &SignalAndSlot::sendMySignal);//将按钮clicked信号与sendMySignal函数绑定
connect(this, &SignalAndSlot::mySignal, this, &SignalAndSlot::getEditTextContent);//将mySignal这个自定义信号与getEditTextContent函数绑定
}
/*发送自定义信号-中间人*/
void SignalAndSlot::sendMySignal()
{
QString text = this->editText->toPlainText();
if (text.isEmpty() == false) {
emit mySignal(text);//如果文本不为空,则将自定义信号发送出去,否则无事发生
}
}
/*获取文本编辑框消息-自定义槽函数*/
void SignalAndSlot::getEditTextContent(QString text)
{
if (text.isEmpty() == false) {//如果消息传递过来的值不为空,则提示消息内容
QMessageBox::information(this, "内容:", text);
}
else {
QMessageBox::warning(this, "Error:", "您还没输入内容呢!!!");
}
}
流程
发送自定义信号
connect(btn, &QPushButton::clicked, this, &SignalAndSlot::sendMySignal);//将按钮clicked信号与sendMySignal函数绑定
当我们单击按钮,由于使用了connect函数,将clicked信号与sendMySignal()函数进行了绑定。
于是单击按钮时,由于按钮被单击后会触发clicked信号,通过connect后,sendMySignal()函数将会被执行,
而从上述代码中可以看到,sendMySignal()函数会获取文本编辑框的内容,然后判断文本是否为空,若不为空,则emit mySignal(text);
在信号中附加编辑框内容的文本数据,将信号发送出去。
接收自定义信号,触发自定义槽函数
connect(this, &SignalAndSlot::mySignal, this, &SignalAndSlot::getEditTextContent);//将mySignal这个自定义信号与getEditTextContent函数绑定
通过上述代码,将mySignal与getEditTextContent函数进行了绑定。那么一切就可以顺其自然的发生了。
由于clicked信号与sendMySignal函数绑定,mySignal信号与getEditTextContent函数绑定。
当clicked信号触发后,sendMySignal槽函数将会获取到文本内容,然后附加到mySignal信号中并发送。而mySignal信号又与getEditTextContent槽函数绑定,所以当mySignal信号触发时,getEditTextContent就会取出信号的文本数据,并用信息框进行展示。
于是当按钮按下后,信息框就会弹出文本编辑框的文本数据。
这就类似于A->B; B->C; 于是可以推出A->C
于是乎,自定义信号与槽的功能就实现了。
自定义信号与槽的关键
其实,如果你足够细心,你应该能够注意到,无论是现实中的接电话案例还是获取获取编辑框的信息,他们都有一个中间人的角色,而这个中间人就是槽函数sendMySignal。
在接电话案例当中,你的大脑就充当了一个中间人的角色,电话铃响,意味着事件发生并且你的大脑监听到了。你选择了接听它说明你的大脑通过电话铃声做出了响应。作出响应的这个过程就对应着自定义槽的函数的实现。
那么怎么判断哪个槽函数是中间人呢?
谁转发的信号,谁就是中间人。
结语
2020 - 996 = 1024
告别996,从1024开始!