QT系列教程(4) Qt 信号和槽

news2024/11/23 9:03:48

信号和槽

当我们需要一个界面通知另一个界面时,可以采用信号和槽机制。通过链接信号和槽,当一个界面发送信号时,链接该信号的槽会被响应,从而达到消息传递的目的。
所以我们先创建一个Qapplication Widgets 应用。Creator会为我们生成mainwindow类和其界面。我们在界面添加一个按钮,按钮的名字叫showChildButton, 按钮显示的文字改为“显示子界面”。
同时为该界面添加一个label,显示的文字修改为“这是主界面”

https://cdn.llfc.club/EBD5635CE2FA.png
现在实现点击按钮,在控制台打印一条日志 "show child dialog "
我们先在MainWindow的构造函数中添加信号和槽的链接逻辑

connect(ui->showChildButton, SIGNAL(clicked(bool)), this, SLOT(showChildDialog()));

然后我们为MainWindow添加showChildDialog槽函数,槽函数需要用slots声明,我们这里在mainwindow.h里用public slots的方式声明槽函数。

public slots:
    void showChildDialog();

接下来去mainwindow.cpp中完成该函数的实现,可以在头文件中右键该函数,在弹出菜单里选择Refactor, 再选择在mainwindow.cpp中添加实现。
https://cdn.llfc.club/645C3ED1042D.png
也可以将鼠标光标放置在这个函数上,按alt+enter,弹出菜单选择在mainwindow.cpp中添加实现。这两种方式都是快捷添加,也可以直接去mainwindow.cpp里实现。

void MainWindow::showChildDialog()
{
    qDebug() << "show child dialog " << endl;
}

运行项目后点击按钮,就可以看到控制台弹出show child dialog日志。

不同的连接方式

我们上边用来连接信号和槽的方式是qt4提供的方式,用SIGNAL和SLOT将信号和槽转化为字符串。
但是这种方式会存在一定问题,Qt要求槽函数的参数不能超过信号定义的参数,比如我们用到的信号clicked(bool)参数就是bool,我们定义的槽函数showChildDialog()是不带参数的,可以连接成功,如果我们在连接的时候将showChildDialog的参数写为3个,也可以连接成功

 //qt4 风格的Slot和Signal 只是宏转换,字符串定义不能检测编译错误
 connect(ui->showChildButton, SIGNAL(clicked(bool)), this, SLOT(showChildDialog(1,2,3)));

但是点击会没有反应,说明qt4 这种连接信号和槽的方式不做编译检查,只是将信号和槽函数转译成字符串。
所以我推荐使用qt5以上版本的连接方式

 //推荐qt5 风格
connect(ui->showChildButton, &QPushButton::clicked, this, &MainWindow::showChildDialog);

这种方式也可以实现信号和槽函数的连接。

实现界面的切换

我们现在实现这样一个demo,程序启动后弹出主界面,点击主界面的按钮弹出子窗口,隐藏主界面,点击子窗口界面的按钮,隐藏子界面,显示主窗口。
所以我们右击项目弹出菜单选择创建Qt设计师界面类,选择Dialog without Buttons,

https://cdn.llfc.club/1661563857494.jpg

名字选择ChildDialog

https://cdn.llfc.club/1661563857494.jpg

我们进入子界面的ui设计界面,添加一个label 描述为这是子界面,添加一个PushButton,文字修改为显示主窗口,并且将按钮的名字修改为showMainWindow
https://cdn.llfc.club/1661736849837.jpg

Qt会为我们创建一个界面类名字叫ChildDialog,我们可以将其作为MainWindow类的成员

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
public slots:
    void showChildDialog();
private:
    ChildDialog *_child_dialog;
};

然后重新改写槽函数,使点击按钮后弹出对话框

void MainWindow::showChildDialog()
{
    qDebug() << "show child dialog " << endl;
    auto _child_dialog = new ChildDialog(this);
    _child_dialog->show();
}

再次运行程序点击显示子界面的按钮,就会弹出子界面了。关闭子界面,再次点击主窗口的显示子窗口按钮,子窗口又显示出来。
这么做有一个问题就是可能会重复创建子窗口,但是Qt的对象树机制会保证父窗口回收时才回收子窗口,所以关闭子窗口只是隐藏了。
那么随着点击,久而久之窗口会越来越多。
我们想到的一个避免重复创建的办法就是在MainWindow的构造函数里创建好子界面,在槽函数中只控制子界面的显示即可。
但同时要注意在MainWindow的析构函数里回收子界面类对象。

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    _child_dialog = new ChildDialog(this);
    connect(ui->showChildButton, &QPushButton::clicked, this, &MainWindow::showChildDialog);
}

MainWindow::~MainWindow()
{
    delete ui;
    if(_child_dialog){
        delete  _child_dialog;
        _child_dialog = nullptr;
    }
}

void MainWindow::showChildDialog()
{
    qDebug() << "show child dialog " << endl;
    _child_dialog->show();
}

这样我们频繁点击显示子界面按钮就不会重复创建窗口了。
那接下来实现点击主界面的按钮,显示子界面,并隐藏主窗口。
实现点击子界面的按钮,显示主窗口,并隐藏子界面。
先实现点击子界面按钮显示主窗口,我们可以在ChildDialog类修改下构造函数,使其接受一个QWidget指针,这个指针指向父窗口也就是MainWindow.
我们新增成员_parent用来存储MainWindow。
新增槽函数showMainWindow用来显示主窗口。

class ChildDialog : public QDialog
{
    Q_OBJECT
public:
    explicit ChildDialog(QWidget *parent = nullptr);
    ~ChildDialog();

private:
    Ui::ChildDialog *ui;
    QWidget *_parent;
public slots:
    void showMainWindow();

};

在ChildDialog的实现文件里连接槽函数,并且实现子界面隐藏,主界面显示

ChildDialog::ChildDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::ChildDialog),_parent(parent)
{
    ui->setupUi(this);
    connect(ui->showMainWindow, &QPushButton::clicked, this, &ChildDialog::showMainWindow);
}

void ChildDialog::showMainWindow()
{
    qDebug() << "show main window" << endl;
    _parent->show();
    this->hide();
}

修改主界面的槽函数,让主界面隐藏,子界面显示

void MainWindow::showChildDialog()
{
    qDebug() << "show child dialog " << endl;
    _child_dialog->show();
    this->hide();
}

运行程序后,点击按钮就可以实现界面的切换。
这么做有一个不好的地方就是在ChildDialog类里保存了MainWindow的指针,如果我们ChildDialog类里要实现和多个其他界面的交互,就需要保存多个指针,这样代码的耦合性太大了。所以我们引入信号和槽机制,当我们点击子界面按钮时发送一个信号给主界面,这样主界面收到该信号后就显示主界面隐藏子界面。
那我们先为ChildDialog类声明一个信号,用来通知主界面显示

class ChildDialog : public QDialog
{
    Q_OBJECT
signals:
   void showMainSig();
public:
    explicit ChildDialog(QWidget *parent = nullptr);
    ~ChildDialog();

private:
    Ui::ChildDialog *ui;
    QWidget *_parent;
public slots:
    void showMainWindow();
};

showMainSig是一个信号,用来通知主界面,所以主界面MainWindow类要连接这个信号,我们先在主界面类中声明这个函数

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
public slots:
    void showChildDialog();
    void showMainDialog();
private:
    ChildDialog *_child_dialog;
};

showMainDialog 是新增的槽函数,用来连接ChildDialog的showMainSig信号。
我们修改ChildDialog的showMainWindow函数

void ChildDialog::showMainWindow()
{
    qDebug() << "show main window" << endl;
    this->hide();
    //可以再次发送信号通知主窗口显示
    emit showMainSig();
}

然后在MainWindow连接这个信号

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    _child_dialog = new ChildDialog(this);
   
    //推荐qt5 风格
    connect(ui->showChildButton, &QPushButton::clicked, this, &MainWindow::showChildDialog);

    connect(_child_dialog, &ChildDialog::showMainSig, this, &MainWindow::showMainDialog);
}

void MainWindow::showChildDialog()
{
    qDebug() << "show child dialog " << endl;
    _child_dialog->show();
    this->hide();
}

再次运行程序,点击按钮实现了界面的切换。

连接信号

上面的程序还可以进一步优化,因为Qt提供了信号连接信号的方式,也就是说我们可以把子界面的按钮点击信号和showMainSig信号连接起来。

ChildDialog::ChildDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::ChildDialog),_parent(parent)
{
    ui->setupUi(this);
    connect(ui->showMainWindow, &QPushButton::clicked, this, &ChildDialog::showMainSig);
}

将clicked和showMainSig两个信号连接起来,也可以实现消息的传递,让代码更简洁了。

总结

视频链接视频教程
源码链接https://gitee.com/secondtonone1/qt-learning-notes

owMainSig两个信号连接起来,也可以实现消息的传递,让代码更简洁了。

总结

视频链接视频教程
源码链接https://gitee.com/secondtonone1/qt-learning-notes

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1601098.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Pytorch入门实战 P06-调用vgg16模型,进行人脸预测

目录 1、本文内容&#xff1a; 1、内容&#xff1a; 2、简单介绍下VGG16&#xff1a; 3、相关其他模型也可以调用&#xff1a; 2、代码展示&#xff1a; 3、训练结果&#xff1a; 1、不同优化器&#xff1a; ①【使用SGD优化器】 ②【使用Adam优化器】 ③Adam 动态学…

Python数据可视化:无向网络图

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 Python数据可视化&#xff1a; 无向网络图 [太阳]选择题 关于以下代码输出结果的说法中正确的是? import networkx as nx import matplotlib.pyplot as plt a [(A, B), (B, C), (B, D)] …

zabbix 自动发现与自动注册 部署 zabbix 代理服务器

zabbix 自动发现&#xff08;对于 agent2 是被动模式&#xff09; zabbix server 主动的去发现所有的客户端&#xff0c;然后将客户端的信息登记在服务端上。 缺点是如果定义的网段中的主机数量多&#xff0c;zabbix server 登记耗时较久&#xff0c;且压力会较大。1.确保客户端…

淘宝API商品详情数据在数据分析行业中具有不可忽视的重要性

淘宝商品详情数据在数据分析行业中具有不可忽视的重要性。这些数据为商家、市场分析师以及数据科学家提供了丰富的信息&#xff0c;有助于他们更深入地理解市场动态、消费者行为以及商品竞争态势。以下是淘宝商品详情数据在数据分析行业中的重要性体现&#xff1a; 请求示例&a…

Customizable Ghosts Pack

“可定制的幽灵包”为游戏开发商快速将幽灵角色融入游戏提供了坚实的基础。鬼角色的标准解决方案。 Customizable Ghost Pack: “可自定义的幽灵包”为游戏开发商快速将幽灵怪物集成到游戏中提供了坚实的基础。鬼角色的标准解决方案。 关键功能 ⭐怪物创造者工具。 ⭐完全…

浅谈Spring的Bean生命周期

在Spring框架中&#xff0c;Bean&#xff08;即Java对象&#xff09;的生命周期涵盖了从创建到销毁的全过程&#xff0c;主要包含以下几个阶段&#xff1a; 实例化&#xff08;Instantiation&#xff09;&#xff1a; 当Spring IoC容器需要创建一个Bean时&#xff0c;首先会通过…

HCIA--综合实验(超详细)

要求&#xff1a; 1. 使用172.16.0.0/16划分网络 2.使用ospf协议合理规划区域保证更新安全 3.加快收敛速度 4. r1为DR没有BDR 5.PC2&#xff0c;3&#xff0c;4&#xff0c;5自动获取IP地址&#xff1b;PC1为外网&#xff0c;PC要求可用互相访问 6.r7为运营商&#xff0c;只能配…

[沫忘录]MySQL索引

[沫忘录]MySQL索引 索引概述 优点 提高数据检索效率&#xff0c;降低数据库IO成本通过索引对数据进行排序&#xff0c;降低数据排序成本&#xff0c;降低CPU消耗 缺点 索引会占用一定空间当更新数据时&#xff0c;也需更新索引数据&#xff0c;这会降低数据的更新效率 索引…

Adobe AE(After Effects)2023下载地址及安装教程

Adobe After Effects是一款专业级别的视觉效果和动态图形处理软件&#xff0c;由Adobe Systems开发。它被广泛用于电影、电视节目、广告和其他多媒体项目的制作。 After Effects提供了强大的合成和特效功能&#xff0c;可以让用户创建出令人惊艳的动态图形和视觉效果。用户可以…

LabVIEW变速箱自动测试系统

LabVIEW变速箱自动测试系统 在农业生产中&#xff0c;采棉机作为重要的农用机械&#xff0c;其高效稳定的运行对提高采棉效率具有重要意义。然而&#xff0c;传统的采棉机变速箱测试方法存在测试效率低、成本高、对设备可能产生损害等问题。为了解决这些问题&#xff0c;开发了…

[docker] 镜像部分补充

[docker] 镜像部分补充 这里补充一下比较少用的&#xff0c;关于镜像的内容 检查镜像 ❯ docker images REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> ca61c1748170 2 hours ago 1.11GB node latest 5212d…

数据中心IP代理VS住宅代理IP,区别详解

一、什么是数据中心/机房IP代理&#xff1f; 数据中心/机房IP代理是使用数据中心拥有并进行分配和管理的IP的代理&#xff0c;俗称机房IP代理。 二、数据中心/机房IP代理的特点 与住宅代理通过使用ISP拥有和分配的IP地址的设备路由请求的情况不同&#xff0c;数据中心代理利…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之一 简单人脸识别

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之一 简单人脸识别 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之一 简单人脸识别 一、简单介绍 二、简单人脸识别实现原理 三、简单人脸识别案例实现简单步…

陇剑杯 流量分析 webshell CTF writeup

陇剑杯 流量分析 链接&#xff1a;https://pan.baidu.com/s/1KSSXOVNPC5hu_Mf60uKM2A?pwdhaek 提取码&#xff1a;haek目录结构 LearnCTF ├───LogAnalize │ ├───linux简单日志分析 │ │ linux-log_2.zip │ │ │ ├───misc日志分析 │ │ …

【蓝桥杯嵌入式】串口通信与RTC时钟

【蓝桥杯嵌入式】串口通信与RTC时钟 串口通信cubemx配置串口通信程序设计 RTC时钟cubemx配置程序设计 串口通信 cubemx配置 打开串口通信&#xff0c;并配置波特率为9600 打开串口中断 重定义串口接收与发送引脚&#xff0c;默认是PC4&#xff0c;PC5&#xff0c;需要改为P…

2024 CKA 基础操作教程(十四)

题目内容 设置配置环境&#xff1a; [candidatenode-1] $ kubectl config use-context mk8s Task 现有的 Kubernetes 集群正在运行版本 1.29.0。仅将 master 节点上的所有 Kubernetes 控制平面和节点组件升级到版本 1.29.1。 确保在升级之前 drain master 节点&#xff0c…

强强联手|AI赋能智能工业化,探索AI在工业领域的应用

随着人工智能&#xff08;AI&#xff09;技术的不断发展和应用&#xff0c;AI在各个领域展现出了巨大的潜力和价值。在工业领域&#xff0c;AI的应用也越来越受到关注。AI具备了丰富的功能和强大的性能&#xff0c;为工业领域的发展带来了巨大的机遇和挑战。 YesPMP是专业的互联…

IAM 统一身份认证与访问管理服务

即统一身份认证与访问管理服务&#xff0c;是云服务商提供的一套云上身份管理解决方案&#xff0c;可帮助企业安全地管理云上资源的访问权限。 在当今云计算时代&#xff0c;企业越来越依赖云服务来存储和处理敏感数据。然而&#xff0c;这也带来了新的安全挑战&#xff0c;即…

1 GBDT:梯度提升决策树

1 前言 前面简单梳理的基本的决策树算法&#xff0c;那么如何更好的使用这个基础算法模型去优化我们的结果是本节要探索的主要内容。 梯度提升决策树&#xff08;Gradient Boosting Decision Trees&#xff09;是一种集成学习方法&#xff0c;通常用于解决回归和分类问题。它通…

v-for中涉及的key

一、为什么要用key&#xff1f; key可以标识列表中每个元素的唯一性&#xff0c;方便Vue高效地更新虚拟DOM&#xff1b;key主要用于dom diff算法&#xff0c;diff算法是同级比较&#xff0c;比较当前标签上的key和标签名&#xff0c;如果都一样&#xff0c;就只移动元素&#…