还没理解Qt的自定义信号与槽吗?快来看这篇文章!

2020/10/27 12:04
阅读数 35

前言

在这里插入图片描述

上个学期由于需要做一个期末大作业,于是决定使用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开始!

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部