[QT编程系列-4]:C++图形用户界面编程,QT框架快速入门培训 - 2- QT程序的运行框架:信号、槽函数、对象之间的通信

news2024/12/26 20:52:46

目录

2. QT程序的运行框架

2.4 设计界面元素的行为:信号、槽函数、对象之间的通信

2.4.1 对象之间的通信

2.4.2 信号槽与消息队里区别

2.4.3 预定义信号与默认槽函数

2.4.4 预定义信号与默认槽函数:案例2

 2.4.5 预定义信号与自定义槽函数:案例3

2.5 界面的切换:隐藏与显示

2.6 界面的关闭


2. QT程序的运行框架

2.4 设计界面元素的行为:信号、槽函数、对象之间的通信

2.4.1 对象之间的通信

 

 

 

 mx:信号、消息

hx:回调的函数指针

obj_x:发送信号和回调函数对应的对象

当对象收到某个事件后,就会查自己内部的事件处理链表,并调用特定对象的成员函数,完成对对象的时间的处理。

在Qt中,槽函数是用于接收信号并执行相应操作的函数。当某个特定事件发生时,例如按钮被点击、文本框内容改变等,与之相关联的信号将被发射。槽函数会在接收到信号时被调用,用于执行相应的逻辑。

以下是使用槽函数的一般步骤:

  1. 在头文件中声明槽函数:在你的类的头文件中声明槽函数。槽函数可以是公有的、私有的或保护的函数。

    class MyClass : public QObject
    {
        Q_OBJECT
    
    public slots:
        void mySlot(); // 声明槽函数
    };
    
  2. 在源文件中实现槽函数:在类的源文件中实现槽函数的具体逻辑。

    void MyClass::mySlot()
    {
        // 槽函数的具体逻辑
    }
    
  3. 将槽函数与信号关联:使用connect函数将槽函数与信号进行关联。这样当信号被发射时,槽函数将被调用。

    MyClass obj;
    QObject::connect(sender, SIGNAL(someSignal()), &obj, SLOT(mySlot()));
    

    在上述代码中,sender是发送信号的对象,someSignal是发送信号的信号名,obj是接收槽函数的对象,mySlot是槽函数的名称。connect函数用于建立信号和槽之间的连接。

注意:

  • 在使用槽函数的类中,需要将 Q_OBJECT 宏加入类的声明中。该宏用于启用Qt的元对象系统,以便支持信号和槽的运行机制。
  • 多个信号可以与同一个槽函数进行连接,也可以一个信号连接到多个槽函数。
  • Qt还提供了一些内置的信号和槽,例如按钮的 clicked() 信号,用于处理按钮点击事件。
  • 槽函数可以有不同数量和类型的参数,但是槽函数的参数必须与信号的参数一致,或者可以自动转换为信号参数类型。
  • 槽函数可以是普通的成员函数,也可以是静态函数。

通过使用槽函数,你可以非常方便地响应并处理Qt应用程序中发生的各种事件与交互动作。

在Qt中,emit关键字用于在发送对象中发射(触发)一个信号。当你在某个类中使用emit关键字时,将调用与之相关联的信号的所有接收对象的槽函数。也就是说,某个接收对象的槽函数是由发送信号的对象,通过rev_obj.slot_function()来实现的。这与消息队列机制是不同的,消息队列机制是由接收方线程检查消息ID, 并根据消息ID来执行接收方的内部函数。

QT中信号+槽函数,类似回调函数的注册和回调,当发送方发送某个信号时,相当于QT框架会检查接收对象关心某个信号的所有接收对象,并调用其先前通过connnect注册的回调函数!!!

在发射信号的过程中,以下是emit的原理:

  1. 信号与槽函数的连接:在信号接收对象的代码中使用connect()函数将信号与接收对象自身的一个或多个槽函数进行连接。这个连接关系通常在对象的构造函数中建立。当信号发射时,与之连接的槽函数将被调用。

  2. 信号的声明和定义:在类的声明中,信号被声明为signals部分。信号的定义包含了信号的名称、参数列表和可能的返回类型。信号的定义告诉Qt元对象系统如何生成信号的运行时代码。

  3. 元对象系统:在编译阶段,Qt的元对象系统会扫描类的声明和定义以生成相关的运行时代码,其中包括信号和槽函数的相关信息。

  4. 运行时发射信号:当使用emit关键字发射信号时,Qt运行时库会检查接收信号的元对象,确定与之相关联的槽函数,并依次调用这些槽函数(在发送对象的线程上下文中调用接收对象的槽函数!!!!,而不是在接收对象的线程的上下文执行槽函数)

总而言之,emit关键字实际上是一个宏,通过元对象系统和信号与槽的连接关系,实现了信号的发射和与之相关联的槽函数的调用。这种设计方式使得Qt中的信号与槽机制成为可能,并提供了一种灵活的方式来处理对象间的通信与交互。

connect函数是Qt中用于建立信号和槽之间连接的方法。通过connect函数,你可以将一个信号与一个或多个槽函数进行关联,以实现对象间的通信。

connect函数有不同的重载形式,常见的形式包括:

  1. 基本形式:connect(sender, SIGNAL(signal), receiver, SLOT(slot))

    • sender:发送信号的对象的指针或对象名。
    • SIGNAL(signal):要连接的信号的名称,可以使用宏SIGNAL()将信号名称转换为字符串。
    • receiver:接收信号的对象的指针或对象名。
    • SLOT(slot):要连接的槽函数的名称,可以使用宏SLOT()将槽函数名称转换为字符串。
  2. Lambda表达式形式:connect(sender, &Sender::signal, receiver, [=](参数列表) { ... })

    • &Sender::signal:要连接的信号的指针,使用&操作符获取信号的指针。
    • receiver:接收信号的对象的指针或对象名。
    • =:传递捕获方式,用于在Lambda表达式中使用当前作用域的变量。
    • (参数列表):指定Lambda表达式的参数列表。
    • { ... }:Lambda表达式的具体实现。

connect函数的返回值是一个bool类型,用于表示连接是否成功。如果连接成功,返回true;如果连接失败,返回false

在使用connect函数时,需要注意以下几点:

  • 在连接信号和槽之前,确保相关的类已经通过Q_OBJECT宏进行声明,以启用Qt的元对象系统支持。
  • 信号和槽必须具有相同的参数列表,或者可以通过自动类型转换进行匹配。
  • 一次连接可以将一个信号连接到一个或多个槽函数,也可以将多个信号连接到一个槽函数。
  • 在断开连接之前,可以使用disconnect函数来取消信号和槽之间的连接。

通过connect函数,你可以实现Qt中强大的信号和槽机制,用于处理对象间的通信和交互。

这种机制使得Qt编程更加灵活和可扩展,提高了代码的可维护性和重用性。

2.4.2 信号槽与消息队里区别

信号槽机制和消息队列是两种不同的通信机制,它们在实现方式和使用场景上有所区别。

信号槽机制是Qt中特有的事件驱动的通信机制,用于在对象之间进行异步的、直接的通信。它通过信号的发射槽函数的调用实现对象之间的通信。一个对象可以发射一个信号,而其他对象可以连接到该信号并响应它,即调用与之关联的槽函数。信号槽机制适用于多个对象之间的实时交互和事件驱动的场景,提供了一种低耦合、高度灵活的通信方式。信号槽本质是注册回调机制!!!用于线程内部的不同对象之间通信或线程间不同对象之间的通信,信号对应的槽函数是在发送信号一端执行的!!!

消息队列是一种更通用的通信机制,可以用于不同类型应用程序和系统之间的通信。在消息队列中,消息是实体的载体,可以包含任意类型的数据。消息生产者将消息发送到队列,并将其放入接收队列中,而消息消费者从队列中获取和处理消息。消息队列通常用于解耦和异步通信,可以在不同的线程、进程甚至不同的计算机之间传递消息。消息队列适用于大型系统、分布式系统和并发编程中。消息id对应的处理函数是在消息的接收端执行的!!!

总结一下,信号槽机制是Qt特有的、用于对象之间的事件驱动通信的机制,而消息队列是一种通用的通信机制,可用于不同类型的应用程序和系统之间的异步通信。根据具体的应用场景和需求,选择合适的通信机制来达到预期的目标。

2.4.3 预定义信号与默认槽函数

 默认的槽函数:被定义在主窗口对象中,而不是控件对象中。

预定义信号:由主窗口对象的控件对象发送。

ConnectSlotsBySlotsName是一种辅助函数,用于在Qt中根据槽函数名称进行信号和槽的连接。

在Qt中,一般使用connect函数来建立信号和槽的连接。它是一种常用的方式,可以根据信号和槽的指针进行连接。

ConnectSlotsBySlotsName函数则提供了另一种方式,通过槽函数的名称来建立信号和槽的连接。它适用于一些特定的场景,比如在运行时动态地建立信号和槽的连接。

使用ConnectSlotsBySlotsName函数时,你需要将一个发送信号的对象、一个接收信号的对象以及槽函数的名称作为参数传入该函数。该函数会在接收信号的对象中查找对应名称的槽函数,并将其与信号进行连接。

下面是一个使用ConnectSlotsBySlotsName的简单示例:

QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(ReceiveSlot()));

在上述代码中,ConnectSlotsBySlotsName函数会在receiver对象中查找名为ReceiveSlot的槽函数,并将其与sender对象发射的名为signal的信号进行连接。

请注意,ConnectSlotsBySlotsName函数是一个由第三方提供的辅助函数,它不是Qt官方库中的一部分。如果你需要使用该函数,请确保你已经在项目中包含了相应的辅助库,并了解其详细的使用方法和限制。

对于默认槽函数,每个发送信号的控件对象,根据控件自身名字+信号的名字,到控件的父窗口中寻找对应的槽函数!!! 

在 Qt 中,有一些默认的槽函数可以用于处理常见的事件和信号。这些默认的槽函数是编写 Qt 应用程序时常用的功能。

以下是一些常见的默认槽函数的示例:

  1. on_<objectName>_<signalName>():这是一种常见的命名约定,用于处理来自特定对象的特定信号。比如,当一个按钮的点击事件被触发时,可以定义一个形如 on_pushButton_clicked() 的函数来处理该事件。
  2. on_<objectName>_clicked():用于处理特定对象的点击事件,如按钮的点击事件。例如,当一个名为 myButton 的按钮被点击时,可以定义一个名为 on_myButton_clicked() 的函数来处理点击事件。
  3. on_<objectName>_activated(<args>):用于处理特定对象的激活事件,如下拉框的选择事件。例如,当一个名为 myComboBox 的下拉框的选择发生变化时,可以定义一个名为 on_myComboBox_activated(<args>) 的函数来处理选择事件。
  4. on_<objectName>_textChanged(const QString &text):用于处理特定对象的文本变化事件,如文本框的内容改变事件。例如,当一个名为 myLineEdit 的文本框的文本内容改变时,可以定义一个名为 on_myLineEdit_textChanged(const QString &text) 的函数来处理文本变化事件。

请注意,以上命名约定不是 Qt 的强制要求,只是一种常见的约定,用于方便识别和管理槽函数。

当然,你也可以根据需要自定义槽函数的名称和参数,以满足特定的需求。

Qt 提供了许多预定义的信号,这些信号是 Qt 类中定义的一些常用事件或状态变化的信号。这些预定义信号可以用于连接到对应的槽函数,以实现特定的功能或响应特定的事件。

以下是一些常见的 Qt 预定义信号的示例:

  1. clicked():当一个按钮被点击时发出的信号。
  2. pressed():当按钮被按下时发出的信号。
  3. released():当按钮被释放时发出的信号。
  4. textChanged(const QString &text):当文本框中的文本发生改变时发出的信号,同时传递新的文本内容。
  5. currentIndexChanged(int index):当下拉框或列表框中当前选中项发生改变时发出的信号,同时传递新选中项的索引。
  6. stateChanged(int state):当复选框或单选按钮的状态发生改变时发出的信号,同时传递新的状态,其中 0 表示未选中,1 表示选中。
  7. objectNameChanged(const QString &objectName):当对象的名称发生改变时发出的信号,同时传递新的对象名称。

这些只是一些常见的预定义信号示例,实际上 Qt 提供了更多的预定义信号,可以根据具体的需要去查看 Qt 类对应的文档以了解更多细节。同时,你也可以自定义信号以满足特定的需求。

 

 

  由主窗口的槽函数接收子控件的信号!!!即事件的发送者是子控件,槽函数的调用者是子控件。槽函数的定义者、接收者、实现者实际是主窗口对象!!!

实际上,与定义槽函数可以定义在任何其他控件对象,也就是说,任意控件对象也可以直接接收其他控件的事件,而不需要通过主窗口对象!!!,即并不需要把信号处理的槽函数定义在主窗口对象中,也可以定义在某个控件对象中,此时,就不需要使用connect进行对象和槽函数的关联!!!

2.4.4 预定义信号与默认槽函数:案例2

 2.4.5 预定义信号与自定义槽函数:案例3

 

 

 

 

在上图中,timer_1s->start(1000)调用开始,就进行计数,当计数满一秒时, timer_1s自动产生并发送一个事件:time_out()。

2.5 界面的切换:隐藏与显示

 

 

 

 

 

 

 

 

2.6 界面的关闭

 

 

 

 备注:

通过this->next把相互独立的窗体给串联起来。

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

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

相关文章

【JVM系列】类加载机制和双亲委派机制(一)

使用java8 一、类加载运行全过程 当我们用java命令运行某个类的main函数启动程序时&#xff0c;首先需要通过类加载器把主类加载到JVM。 package jvmdemo;public class Math {public static final int initData 666;public static User user new User();public int comput…

立创EDA(专业版)电路设计与制作快速入门

1.新建工程的时候 &#xff08;要注意用版本控制&#xff0c;项目名&#xff0c;日期&#xff0c;版本&#xff09; 2.原理图设计环境设置 3.电源转换电路 电源是一般是5v转3.3v电路 电源主要的可以选择LLDO来降压的或者是DCDC减压 这个电路主要是用LDO来降压的 AMS1117降…

操作系统Linux—day01

编程 网页 软件 网站项目 知识点&#xff1a; 前端页面&#xff1a;HTML css JavaScript JQuery VUE 数据库&#xff1a;Oracle MySQL 服务器&#xff1a;服务器的操作系统Linux Http://115.159.96.174:8090/EasyBuy/ www.baidu.com>http://180.101.49.12/ 后台技术…

【iOS】消息传递

Objective-C是一种动态语言&#xff0c;因此其很多行为是在运行时决定的。对于静态语言来说&#xff0c;函数的调用在编译时就已经确定。动态语言则不然&#xff0c;动态语言通过一些巧妙的机制使得函数的真实调用是在运行时决定的&#xff0c;即动态语言的特点是将一些决定性的…

2、常用基本命令-文件

Shell 可以看作是一个命令解释器&#xff0c;为我们提供了交互式的文本控制台界面。我们可以 通过终端控制台来输入命令&#xff0c;由 shell 进行解释并最终交给内核执行。 本章就将分类介绍 常用的基本 shell 命令。 7.1 帮助命令 7.1.1 man 获得帮助信息 1&#xff09;基本…

大于100万行数据如何转换坐标、格网生成和裁剪、低格网数据提取

在工作过程中&#xff0c;对于100万以下的数据&#xff0c;我们一般使用EXCEL进行操作&#xff0c;但对于大于1百万行的数据&#xff0c;EXCEL也无能为力。此时&#xff0c;解决办法有三种&#xff1a;&#xff08;1&#xff09;拆分成几个小于100万的文件&#xff0c;再用EXCE…

机器学习原理

此次主要是由分类来引出 由于宝可梦的图片比较简洁&#xff0c;而数码宝贝的图片就显得比较复杂&#xff0c;我们计算出他们的轮廓&#xff0c;求出白色数量的多少。 e的函数会计算线条的复杂程度。当得出的线条的复杂程度&#xff0c;小于h。我们认为其是宝可梦&#xff0c;反…

Python(七)二进制

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

Mac非brew方式安装OpenResty教程

本文版本基于openresty-1.15.8.1和pcre-8.4.4安装。 一、安装前准备 由于openResty本质上还是基于nginx和Lua的高性能Web平台&#xff0c;安装openResty前需要先安装好openssl和pcre。 小编的机器因为之前安装过nginx&#xff0c;所以openssl和pcre已经有了。openssl的安装目…

Python(六)转义字符和原字符

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

包管理工具:npm、yarn、cnpm、npx、pnpm

yarn&#xff1a;  yarn是由Facebook(react)、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具&#xff1b;  yarn 是为了弥补早期npm 的一些缺陷而出现的&#xff1b;  早期的npm存在很多的缺陷&#xff0c;比如安装依赖速度很慢、版本依赖混乱等等一系列…

【LeetCode: 1911. 最大子序列交替和 | 暴力递归=>记忆化搜索=>动态规划 】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

【C#】设置输入法,解决扫描枪在中文状态下识别异常问题

系列文章 【C#】编号生成器&#xff08;定义单号规则、固定字符、流水号、业务单号&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129129787 【C#】日期范围生成器&#xff08;开始日期、结束日期&#xff09; 本文链接&#xff1a;h…

【Redis】特殊数据类型 Stream (流)

&#x1f3af;前言 除了五中基本的数据类型外&#xff0c;Redis还支持两种特殊的数据类型&#xff0c;第一种 Geo (地理位置)&#xff1a;用于存储地理位置相关的数据&#xff0c;例如经纬度、距离等。第二种 Stream (流)&#xff1a;是一个高级的列表类型&#xff0c;支持对列…

学习系统编程No.30【多线程控制实战】

引言&#xff1a; 北京时间&#xff1a;2023/7/7/9:58&#xff0c;耳机正在充电中&#xff0c;所以刚好让我们先把引言写一写&#xff0c;昨天睡觉前听了一会小说&#xff0c;听小说的好处就在于&#xff0c;它可以让你放下手机&#xff0c;快速睡觉&#xff0c;并且还有一定的…

python批量检测网站是否能打开

import requestsif __name__ "__main__":file_name input() #读取文件名fp1 open(file_name, "r") #以只读&#xff0c;打开文件for line in fp1.readlines(): #readlines 按行读取文件&#xff0c;会保留\n&#xff0c;返回一个(文…

3. MySQL - 数据类型 选项约束

目录 回顾 1. 命令行下的 MySql 客户端 2. 图形化界面的 MySQL-Client 3. 数据库概述 3.1 数据库管理系统是什么 3.2 工作模式 3.3 RDBMS 管理数据的结构 3.4 客户端连接服务器的信息 4. MySQL 中的数据类型 4.1 整型类型 4.2 字符串 4.3 日期/时间 5. MySQL 每个字…

【Ubuntu18.04 解决蓝牙wifi 之ax201无线网卡驱动安装】

【Ubuntu18.04 解决蓝牙wifi 之ax201无线网卡驱动安装】 1. 前言2. 更新linux内核 3. 下载安装intel ax201网卡驱动 1. 前言 台式机安装了双系统win11Ubuntu18.04系统&#xff0c;发现没有无线网卡和蓝牙&#xff0c;经查阅资料发现由于网卡刚没多久&#xff0c;Ubuntu没有集成…

服务器反向代理

反向代理作用 隐藏服务器信息 -> 保证内网的安全&#xff0c;通常将反向代理作为公网访问地址&#xff0c;web服务器是内网&#xff0c;即通过nginx配置外网访问web服务器内网 举例 百度的网址是&#xff1a;http://www.baidu.com &#xff0c; 现在我通过自己的服务器地…

Figma源文件导出技巧:提升效率的简易步骤

因为Figma&#xff0c;sketch,xd都支持导入sketch格式,所以我们只要将文件格式转成sketch&#xff0c;就能自由的在不同软件间导入导出。 现在就有一个网站可以帮助你快速简单的导入Figma、Sketch、XD 等格式文件&#xff0c;&#xff0c;还可以导出 Sketch 文件满足跨工具协作…