C++ Qt开发:如何使用信号与槽

在Qt中,信号与槽(Signal and Slot)是一种用于对象之间通信的机制。是Qt框架引以为傲的一项机制,它带来了许多优势,使得Qt成为一个强大且灵活的开发框架之一。信号与槽的关联通过QObject::connect函数完成。这样的机制使得对象能够以一种灵活而松散耦合的方式进行通信,使得组件之间的交互更加灵活和可维护。

信号(Signal) 是一种特殊的成员函数,用于表示某个事件的发生。当特定的事件发生时,对象会发射(emit)相应的信号。例如,按钮被点击、定时器时间到达等都可以是信号。

槽(Slot) 是用于处理信号的成员函数。槽函数定义了在特定信号发生时执行的操作。一个槽可以与一个或多个信号关联,当信号被发射时,与之关联的槽函数将被调用。

在早期,对象间的通信采用回调实现。回调实际上是利用函数指针来实现,当我们希望某件事发生时处理函数能够获得通知,就需要将回调函数的指针传递给处理函数,这样处理函数就会在合适的时候调用回调函数。回调有两个明显的缺点:

  • 它们不是类型安全的,无法保证处理函数传递给回调函数的参数都是正确的。
  • 回调函数和处理函数紧密耦合,源于处理函数必须知道哪一个函数被回调。

而信号与槽机制则可以更好的比秒上述问题的产生,以下是信号与槽机制的一些优势:

  1. 松散耦合(Loose Coupling): 信号与槽机制实现了松散耦合,使得对象之间的连接更加灵活。对象不需要知道彼此的具体实现,只需通过信号与槽进行通信。这降低了组件之间的依赖关系,提高了代码的可维护性。
  2. 事件驱动(Event-Driven): 信号与槽机制使得Qt应用程序能够轻松地处理事件。例如,按钮的点击、定时器的超时等都可以通过信号与槽来处理,使得应用程序能够响应用户交互和外部事件。
  3. 模块化设计: 通过信号与槽,不同模块之间可以通过事件进行通信,这样可以更容易地设计和维护模块化的代码。一个模块的改变不太可能影响到其他模块,从而提高了代码的可维护性。
  4. 异步通信: 信号与槽机制支持跨线程的异步通信。当信号与槽连接在不同线程的对象上时,Qt会自动进行线程间的通信,使得开发者能够更方便地处理多线程应用。
  5. 灵活的连接方式: Qt支持多种连接方式,包括在代码中使用QObject::connect连接,也可以使用Qt Creator等工具在图形界面上进行可视化的信号与槽关联。这种灵活性使得开发者可以选择最适合他们需求的连接方式。
  6. 类型安全的连接(Qt5新增特性): 在Qt5中引入了新的connect语法,不再需要使用SIGNAL()和SLOT()宏,而是使用函数指针直接进行连接,从而在编译时进行类型检查,减少了潜在的运行时错误。

总体而言,这些优势使得Qt成为构建各种类型应用程序的理想选择。

1.1 信号与槽函数

1.1.1 Connect

信号和槽进行关联使用的是QObject类的connect()函数,QObject::connect 是用于建立信号与槽连接的Qt框架函数。它有几个不同的重载形式,但最常用的形式是:

static QMetaObject::Connection QObject::connect(const QObject *sender,const char *signal,const QObject *receiver,const char *slot,Qt::ConnectionType type = Qt::AutoConnection
);

参数解释如下:

  • sender:发出信号的对象指针。
  • signal:信号的签名,使用 SIGNAL 宏包装,指定了发出的信号。
  • receiver:接收信号的对象指针。
  • slot:槽函数的签名,使用 SLOT 宏包装,指定了接收到信号时要调用的函数。
  • type:连接的类型,是一个枚举值,可以是 Qt::AutoConnectionQt::DirectConnectionQt::QueuedConnectionQt::BlockingQueuedConnection

在函数定义中,第一个参数sender为发送信号的对象,第二个参数signal为要发送的信号,第三个参数receiver为接收信号的对象,第4个参数slot为接收对象在接收到信号之后所需要调用的槽函数。该函数的最后一个参数表明了关联的方式,默认值是Qt::AutoConnection方式,函数最终返回值是一个 QMetaObject::Connection 对象,可以用于断开连接时使用。

这个函数的作用是将 sender 对象的 signalreceiver 对象的 slot 进行连接。当 sender 发出信号时,receiver 对象的 slot 函数将被调用。

1.1.2 Disconnect

QObject::disconnect 是 Qt 框架用于断开信号与槽连接的函数。它有几个不同的重载形式,但最常用的形式是:

static bool QObject::disconnect(const QObject *sender,const char *signal,const QObject *receiver,const char *slot
);

参数解释如下:

  • sender:发出信号的对象指针。
  • signal:信号的签名,使用 SIGNAL 宏包装,指定了发出的信号。
  • receiver:接收信号的对象指针。
  • slot:槽函数的签名,使用 SLOT 宏包装,指定了接收到信号时要调用的函数。

这个函数的作用是断开 sender 对象的 signalreceiver 对象的 slot 之间的连接。如果连接存在,那么它将被断开,不再触发。该函数返回值是一个 bool 类型,表示是否成功断开连接。

1.2 应用信号与槽

1.2.1 信号与槽绑定

信号与槽函数的使用非常容易理解,笔者将以最简单的案例来告诉大家该如何灵活的运用这两者,首先新建一个Qt Widgets Application项目,如下图所示第一个则是该项目的选项卡,其他参数保持默认即可;

当项目被创建好之后读者应该能构建看到如下图所示的页面提示信息,其中的untitled.pro是项目的主配置文件该配置文件一般有Qt自动维护,文件夹Headers则是项目的头文件包含路径,Sources则是代码的实现路径,最后一个Forms是用于图形化设计的UI模板。

首先双击mainwindow.ui进入到UI设计模式,接着拖拽一个PushButton按钮组件,与两个lineEdit组件到右侧的窗体画布上,并按下Ctrl+S保存该画布,刷新配置文件,如下图所示;

此时回到编辑菜单,并点击mainwindow.h头文件部分,并在头文件mainwindow.h的类MainWindow的定义中声明槽函数,代码如下,其含义是定义一个按钮点击槽:

public slots:void on_pushButton_clicked();

接着我们就需要点击mainwindow.cpp文件,并在头文件中实现这个槽函数的具体功能,此处我们就实现设置两个lineEdit组件分别用于显示两串字符串,代码如下;

void MainWindow::on_pushButton_clicked()
{ui->lineEdit->setText("hello lyshark");ui->lineEdit_2->setText("www.lyshark.com");
}

最后一步则是建立映射关系,在类MainWindow的构造函数中添加如下语句,以便将信号和槽函数进行连接:

#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 建立关联当点击pushButton时信号clicked 发送给槽on_pushButton_clickedconnect(ui->pushButton,SIGNAL(clicked()),this,SLOT(on_pushButton_clicked));
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_pushButton_clicked()
{ui->lineEdit->setText("hello lyshark");ui->lineEdit_2->setText("www.lyshark.com");
}

此时运行程序,当读者点击按钮时,则会自动触发on_pushButton_clicked()所关联的代码,将两个lineEdit设置为不同的内容,如下图;

当然了,上述过程都是需要我们手动的去关联信号与槽,在开发中其实可以直接在PushButton组件上邮件,选中转到槽选项,此时则会弹出关于该组件所支持的所有槽函数,读者只需要选中并双击,即可自动实现槽函数的创建与管理,这对于高效率开发是至关重要的。

当然在槽函数使用结束后我们需要断开,在断开时直接使用disconnect并传入需要断开的绑定sender信号即可,如下所示;

void MainWindow::on_pushButton_2_clicked()
{disconnect(ui->pushButton,SIGNAL(clicked()),nullptr,nullptr);
}

1.2.2 匿名函数绑定

你是否感觉使用代码创建信号与槽很麻烦呢,其实通过使用Lambda表达式我们可以与Connect完美的结合在一起使用,者能够让信号与槽的使用更加的得心应手。

Lambda表达式是一种匿名函数的表示方式,引入C++11标准,用于创建内联函数或闭包。Lambda表达式可以在需要函数对象的地方提供一种更为简洁和灵活的语法。

它的基本形式如下:

[capture](parameters) -> return_type {// 函数体
}
  • capture:用于捕获外部变量的列表。可以捕获外部变量的值或引用,也可以省略不捕获任何变量。捕获列表是Lambda表达式的一部分。
  • parameters:参数列表,类似于普通函数的参数。
  • return_type:返回类型,指定Lambda表达式的返回类型。可以省略,由编译器自动推断。
  • {}:Lambda表达式的函数体。

使用Lambda表达式与Qt的connect函数结合实现匿名槽函数。具体概述如下:

Lambda表达式的初始化

[=]() {this->setWindowTitle("初始化..");
}();

这里使用Lambda表达式对 this->setWindowTitle("初始化.."); 进行了初始化,Lambda表达式中的 [=] 表示捕获外部变量并通过值传递,其中的 () 表示Lambda表达式立即执行,实现对窗口标题的初始化。

Lambda表达式作为槽函数

connect(btn_ptr1, &QPushButton::clicked, this, [=]() mutable {number = number + 100;std::cout << "inner: " << number << std::endl;
});

这里使用Lambda表达式作为 btn_ptr1 按钮的槽函数。在Lambda表达式中,使用了 mutable 关键字,允许修改通过值传递的变量 number。当按钮 btn_ptr1 被点击时,Lambda表达式内部修改了 number 的值,并输出修改后的值。

Lambda表达式中的返回值

int ref = []() -> int {return 1000;
}();
std::cout << "Return = " << ref << std::endl;

这里的Lambda表达式中带有返回值的情况。Lambda表达式通过 -> int 指定返回类型,然后在大括号中返回了一个整数值。该Lambda表达式被立即执行,返回值被赋给变量 ref,并输出到控制台。

如下,我们就来演示一个简单的直接使用匿名函数实现功能的案例,当使用匿名函数时,只需要在Connect时将功能一并写到链接函数的底部即可,此时的效果等同于上述功能,因为没有函数名所以显得更加简单,如下图;

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 匿名函数connect(ui->pushButton,&QPushButton::clicked,this,[=](){std::cout << "hello lyshark" << std::endl;ui->lineEdit->setText("www.lyshark.com");});
}

总体来说,匿名函数(Lambda表达式)在Qt中与connect函数一起使用,提供了一种方便的方式来定义简短的槽函数,使得代码更加紧凑和可读。

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

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

相关文章

Leetcode 2957. Remove Adjacent Almost-Equal Characters

Leetcode 2957. Remove Adjacent Almost-Equal Characters 1. 解题思路2. 代码实现 题目链接&#xff1a;2957. Remove Adjacent Almost-Equal Characters 1. 解题思路 这一题其实不是很想放上来的&#xff0c;因为其实真的很简单&#xff0c;但是我惊讶地发现当前提交的算法…

【EI会议征稿】第三届光学与机器视觉国际学术会议(ICOMV 2024)

第三届光学与机器视觉国际学术会议(ICOMV 2024) 2024 3rd International Conference on Optics and Machine Vision 第三届光学与机器视觉国际学术会议(ICOMV 2024)将于2024年1月19-21日在中国南昌举行。本次会议将围绕“光学”与"机器视觉”等研究领域展开讨论&#xf…

kmp算法超详细

在计算机科学中&#xff0c;字符串匹配是一个常见的问题。给定一个文本串和一个模式串&#xff0c;我们需要在文本串中找到所有与模式串匹配的位置。传统的字符串匹配算法如暴力匹配&#xff08;Brute Force&#xff09;方法在最坏情况下的时间复杂度为O(m*n)&#xff0c;其中m…

Java实现minio

配置Dapplication.yml minio:access-key: minioadminsecret-key: minioadminbucket-name: file #指定桶名称endpoint: http://localhost:9000 实现代码minioContriller.java package com.setsail.setsailcusserver.controller;import com.alibaba.fastjson.JSONObject; impo…

万界星空科技五金家具行业MES解决方案

MES系统如何与家具企业生产相匹配&#xff1f;相较于其它大多数工业软件&#xff0c;MES系统无疑是受企业欢迎的软件之一。MES系统处于制造生产企业信息化的核心领域&#xff0c;有着承上启下的作用。那MES系统如何与家具企业生产相匹配&#xff1f; 五金家具行业的工艺特点&am…

最简单的pixel刷机和安装面具、lsposed

一 下载手机对应的系统 1&#xff0c;手机usb连接然后重启进入Fastboot模式&#xff1a;adb reboot bootloader2&#xff0c;找到你下载的系统&#xff0c;Windows 系统 直接运行 flash-all.bat上图 &#xff1a;左边就是安卓11和12的系统&#xff0c;右边是对应的手机型号 下…

mysql:修改整数字段的显式长度不生效

例如&#xff0c;我使用mysql 8.2.0版本&#xff0c;想修改整数字段的显式长度&#xff0c;不会生效&#xff0c;提醒整数的显示长度已经废弃&#xff0c;会在将来某个版本去掉&#xff1a; mysql官网中也有说明&#xff1a; https://dev.mysql.com/doc/refman/8.2/en/numeric…

带阻滤波器:原理、应用及性能分析?|深圳比创达电子EMC

在现代电子技术和通信领域中&#xff0c;滤波器是一种常见的电路元件&#xff0c;用于处理信号&#xff0c;去除不需要的频率成分或者增强感兴趣的频率成分。本文将重点探讨带阻滤波器&#xff0c;它是一种特殊类型的滤波器&#xff0c;具有在特定频率范围内抑制信号的功能。我…

SSD自己也能复制粘贴?浅谈NVMe 2.0 Copy Command命令

复制粘贴&#xff08;CtrlC/V&#xff09;作为现代打工人日常办公的必备生存技能&#xff0c;想必大家都非常熟悉。但你知道吗&#xff0c;其实SSD自身也能进行这个非常实用的操作。可能有的读者要说了&#xff1a;这有什么稀奇&#xff0c;复制粘贴这么简单的功能&#xff0c;…

腾讯字节常考的linux命令

1 ps 1.1 ps -ef 有哪些字段 ps -ef 命令在Unix/Linux系统中用于显示当前运行的进程。输出的字段通常包括&#xff1a; UID&#xff1a;启动进程的用户ID。PID&#xff1a;进程ID。PPID&#xff1a;父进程ID。C&#xff1a;CPU利用率。STIME&#xff1a;进程启动时间。TTY&a…

安卓上比iOS快捷指令更强大的工具——MacroDroid

使用 MacroDroid (Android) 自动化您的日常生活——一个简单的自动化应用程序&#xff0c;用于在 Android 上自动执行任务以及如何在其上自动执行任务。 iOS 和 Android 之间的区别? iOS和Android是两种不同的移动操作系统&#xff0c;iOS由苹果公司开发&#xff0c;于2007年…

conda配环境问题合集

&#xff08;CtrlF&#xff0c;请&#xff09; 问题&#xff1a; File "F:\Anaconda3\envs\YOLOv5\lib\ssl.py", line 773, in __init__ raise ValueError("check_hostname requires server_hostname") ValueError: check_hostname requires server_h…

Vue2解决pinia刷新后数据丢失的问题

Pinia&#xff1a;官网 Pinia 是一个 Vue.js 状态管理库&#xff0c;如果你在组件中修改了 store 中的数据并刷新了界面&#xff0c;Pinia 会将 store 中的数据重置为初始值&#xff0c;从而导致数据丢失的问题。 这里给出vue2的解决方案&#xff1a; 可以使用 Pinia 的 Per…

当接口要加入新方法时,我后悔没有早点学设计模式了

&#x1f4e2; 声明&#xff1a; &#x1f344; 大家好&#xff0c;我是风筝 &#x1f30d; 作者主页&#xff1a;【古时的风筝CSDN主页】。 ⚠️ 本文目的为个人学习记录及知识分享。如果有什么不正确、不严谨的地方请及时指正&#xff0c;不胜感激。 直达博主&#xff1a;「…

PP材料粘接ABS材料使用UV胶的好处?

跟随着现阶段材料的不断发展更迭&#xff0c;PP材料应用越来越广&#xff0c;生产效率要求越来越高&#xff0c;为了加快生产&#xff0c;提高效率&#xff0c;PP材料的粘接上使用UV胶粘接PP&#xff08;聚丙烯&#xff09;和ABS&#xff08;丙烯腈-丁二烯-苯乙烯共聚物&#x…

python Open3D加载obj

pip安装Open3D python -m pip install open3d示例代码 import numpy as np import open3d as o3dpath_obj test/assimp-5.2.5/test/models/OBJ/box.objmesh o3d.io.read_triangle_mesh(path_obj, enable_post_processingTrue)print(np.asarray(mesh.vertices))mesh.compute…

Jenkins:持续集成与持续交付的自动化利器

随着软件开发行业的快速发展&#xff0c;持续集成&#xff08;Continuous Integration&#xff0c;简称CI&#xff09;和持续交付&#xff08;Continuous Delivery&#xff0c;简称CD&#xff09;已经成为了现代软件开发的重要理念。Jenkins作为一款开源的持续集成和持续交付工…

企业可以利用SD-WAN打破网络限制,实现高效稳定的应用访问

在当今数字化时代&#xff0c;我们面临着越来越多复杂应用和各种类型的数据传输。企业需要实时访问云应用、视频会议等关键应用&#xff0c;不断增长的访问流量&#xff0c;导致应用访问速度变得越来越慢&#xff0c;给工作效率和用户体验带来了很大困扰。 SD-WAN是否能够解决这…

javaSwing酒店管理

一、介绍 在这篇博客中&#xff0c;我们将介绍一个基于MySQL数据库、Java编程语言和Swing图形用户界面的简单酒店管理系统。该系统包括了查询房客信息、查询房客状态、修改房客信息、添加房间信息、添加住户、退房管理、预定管理、退订管理、入账管理、出账管理、修改资料等多…

0009Java程序设计-ssm微信小程序在慢性疾病管理中的应用

文章目录 **摘要**目录系统实现开发环境 编程技术交流、源码分享、模板分享、网课分享 企鹅&#x1f427;裙&#xff1a;776871563 摘要 首先,论文一开始便是清楚的论述了小程序的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例…