Qt信号与槽原理

2023-11-13

Qt信号与槽原理

本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:黄勇)

本文出自本人原创著作《Qt5.10 GUI完全参考手册》网盘地址:
https://pan.baidu.com/s/1iqagt4SEC8PUYx6t3ku39Q
《C++语法详解》网盘地址:https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg

若对C++语法不熟悉,建议参阅本人所著《C++语法详解》一书,电子工业出版社出版,该书语法示例短小精悍,对查阅C++知识点相当方便,并对语法原理进行了透彻、深入详细的讲解,可确保读者彻底弄懂C++的原理,彻底解惑C++,使其知其然更知其所以然。此书是一本全面了解C++不可多得的案头必备图书。

信号和槽是用于对象之间的通信的,这是Qt的核心。为此Qt引入了一些关键字,他们是slots、signals、emit,这些都不是C++关键字,是Qt特有的,这些关键字会被Qt的moc转换为标准的C++语句。Qt的部件类中有一些已经定义好了的信号和槽,通常的作法是子类化部件类,然后添加自已的信号和槽。
因为信号和槽与函数相似,所以通常把信号称为信号函数,槽称为槽函数。

2.4.1 信号和槽原理

C++虽然是面象对象的语言,但程序的具体实现代码仍然是由函数来实现的,因此所谓的对象之间的通信,从程序设计语言语法角度来看就是函数调用的问题,只不过是某个对象的成员函数调用另一个对象的成员函数而已,本文从语法角度讲解信号和槽的原理,这样更容易理解信号和槽的实现原理。注:信号和槽其实是观察者模式的一种实现,有兴趣的读者可以参阅《设计模式》课程。
函数调用的几种形式
在这里插入图片描述
见图2-1,假设函数f需要g的处理结果,有以下几种处理方式
① 最简单的方式就是直接调用函数g,但这种方式有一个明显的缺点,必须知道函数g的名称“g”以及函数g的参数类型。但是若f只需要g的处理结果就可以了,而g的处理结果不一定需要函数g来完成,它也可以是x、y或其他函数来完成,那么这种直接调用函数的方式就无法胜任了,因为系统不知道用户会使用哪个函数来完成这种处理结果,也就是系统不知道调用的函数名究竟是g、x或其他名称。
② 另一种方式就是回调函数,即在函数f中使用一个指向函数的指针去调用需要的函数,这样就可以调用任意名称的函数(只要函数类型与指针相同即可),此时只要是完成了函数g功能的函数都可以作为函数f的结果被调用,这样就不会被函数名称所限制。比如
在这里插入图片描述
③ Qt使用的信号和槽机制
注意:信号和槽不是C++标准代码,因此这些代码需要使用Qt的moc进行重新编译。 其基本思想如下:
 创建一个信号,其中创建信号需要一些规则。
 当需要调用外部函数时,发送一个信号,
 此时与该信号相关联的槽便会被调用,槽其实就是一个函数,当然要使函数成为槽是有一定规则的。槽与信号的关联需要由程序员来完成。
 在Qt中,信号和槽都需要位于类之中。
 示例(具体实现时Qt引入了一些新的关键字):
在这里插入图片描述

2.4.2 创建信号和槽

只有QObject及其派生类才能使用信号和槽机制,且在类之中还需要使用Q_OBJECT宏。
1、信号需符合以下规则
 信号使用signals关键字声明,在其后面有一个冒号“:”,在其前面不能有public、private、protected访问控制符,信号默认是public的。
 信号只需像函数那样声明即可,其中可以有参数,参数的主要作用是用于和槽的通信,这就像普通函数的参数传递规则一样。信号虽然像函数,但是对他的调用方式不一样,信号需要使用emit关键字发送。
 信号只需声明,不能对其进行定义,信号是由moc自动生成的。
 信号的返回值只能是void类型的。
2、声明槽需符合以下规则
 声明槽需要使用slots关键字,在其后面有一个冒号“:”,且槽需使用public、private、protected访问控制符之一。
 槽就是一个普通的函数,可以像使用普通函数一样进行使用,槽与普通函数的主要区别是,槽可以与信号关联。
3、发射信号需符合以下规则:
 发射信号需要使用emit关键字,注意,在emit后面不需要冒号。
 emit发射的信号使用的语法与调用普通函数相同,比如有一个信号为void f(int),则发送的语法为:emit f(3);
 当信号被发射时,与其相关联的槽函数会被调用(注意:信号和槽需要使用QObject::connect函数进行关联之后,发射信号后才会调用相关联的槽函数)。
 注意:因为信号位于类之中,因此发射信号的位置需要位于该类的成员函数中或该类能见到信号的标识符的位置。
4、信号和槽的关系
 槽的参数的类型需要与信号参数的类型相对应,
 槽的参数不能多余信号的参数,因为若槽的参数更多,则多余的参数不能接收到信号传递过来的值,若在槽中使用了这些多余的无值的参数,就会产生错误。
 若信号的参数多余槽的参数,则多余的参数将被忽略。
 一个信号可以与多个槽关联,多个信号也可以与同一个槽关联,信号也可以关联到另一个信号上。
 若一个信号关联到多个槽时,则发射信号时,槽函数按照关联的顺序依次执行。
 若信号连接到另一个信号,则当第一个信号发射时,会立即发射第二个信号。
因Qt在其类库中预定义了很多信号和槽,因此在Qt中可以仅使用Qt类库中预定义的信号和槽,也可以只使用Qt类库中预定义的信号而使用自已的槽,也可以使用Qt类库中预定义的槽来响应自已定义的信号,当然,槽和信号也都可以使用自定义的。

示例2.10:创建信号和槽
//头文件m.h的内容

#ifndef M_H   
#define M_H
#include<QObject>
#include <iostream>
using namespace std;

class A:public QObject{   //信号和槽必须继承自QObject类
Q_OBJECT             //必须添加该宏
//public signals:void s1(int);  //错误signals前不能有访问控制符。
  	signals:void s();          //使用signals关键字声明信号,信号的语法与声明函数相同。
    	signals:void s(int,int);   //正确,信号可以有参数,也可以重载。
        //void s2(){}          //错误,信号只需声明,不能定义。
        	void s3();           //注意:这仍是声明的一个信号
public:                //信号声明结束后,重新使用访问控制符,表示以下声明的是成员函数。
    		void g(){
emit s3();   /*发射信号,其语法与调用普通函数相同,在信号与槽关联之前,发射的信号不会调用相应的槽函数。*/
// emit: s3();  //错误,emit后不能有冒号。
  	  }};

class B:public QObject{   Q_OBJECT
public slots:                 //使用slots关键字声明槽
void x(){cout<<"X"<<endl;}  /*正确,槽就是一个普通函数,只是需要使用slots关键字,且能和信号相关联。*/
  		//slots: void x(){}   //错误,声明槽时需要指定访问控制符。
     public:
         void g(){ // emit s3();  //错误,在类B中对于标识符s3是不可见的
        		 }	};
#endif // M_H

//源文件m.cpp的内容

#include "m.h"
int main(int argc, char *argv[]){    A ma;    B mb;
    QObject::connect(&ma,&A::s3,&mb,&B::x);  //关联信号和槽,详见后文
    ma.g();   //调用对象mb的成员函数x输出X,可见对象ma和mb之间实现了通信。
    return 0;	}

2.4.3 信号和槽的关联(连接)

信号和槽使用QObject类中的成员函数connect进行关联,该函数有多个重载版本,如下所示。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6、形式3与形式1的区别

① 形式1的SINGAL和SLOT宏实际是把该宏的参数转换为字符串,当信号和槽相关联时,使用的是字符串进行匹配,因此,信号和槽的参数类型的名字必须在字符串意义上相同,所以信号和槽无法使用兼容类型的参数,也因此也不能使用typedef或namespace的类型,虽然他们的实际类型相同,但由于字符串名字不同,从而无法使用形式1。
② 形式3的信号和槽函数的参数类型不需完全一致,可以进行隐式转换。形式3还支持typedef和命名空间。
③ 形式3以指针的形式指定信号和槽函数,不需再使用SIGNAL()和SLOT宏。
④ 形式3的槽函数可以不使用slots关键字声明,任意的成员函数都可以是槽函数。形式1的槽函数必须使用slots修饰。
⑤ 形式1的槽函数不受private的限制,也就是说即使槽是private的,仍可通过信号调用该槽函数,而形式3则在使用connect时就会发生错误。
⑥ 当信号或槽函数有重载的形式时,使用形式3可能会产生二义性错误,此时可使用函数指针的形式指定信号或槽函数,或者使用形式1,比如
在这里插入图片描述

示例2.11:信号和槽的关联

//头文件m.h的内容
#ifndef M_H
#define M_H
#include<QObject>
#include <iostream>
using namespace std;

class A:public QObject{		 Q_OBJECT
    signals:void s();    void s(int,int);    void s1();    void s2(int);	 };
class B:public QObject{   Q_OBJECT
public slots:
        void x(){cout<<"x"<<endl;}         	void y(int i,int j){cout<<"y="<<i<<j<<endl;}
        void z(int){cout<<"zi"<<endl;}      void z1(float){cout<<"z1f"<<endl;}
 	public:
         void z2(){   //注意,该函数未使用slots声明。
            		cout<<"z2"<<endl; }
private slots:            //私有槽
void z3(){     cout<<"z3"<<endl;        }	};
#endif // M_H

//源文件m.cpp的内容

#include "m.h"
int main(int argc, char *argv[]){    A ma;    B mb;
    QObject::connect(&ma,SIGNAL(s()),&mb,SLOT(x()));  //形式1
    emit ma.s();    //输出x
    QObject::connect(&ma,&A::s1,&mb,&B::x);  //形式3
    emit ma.s1();   //输出x
   // QObject::connect(&ma,&A::s1,&mb,&B::y);  //错误,槽参数的数量多余信号参数的数量
//类型转换
	//关联失败,形式1不支持类型转换
   	//QObject::connect(&ma,SIGNAL(s2(int)),&mb,SLOT(z1(float)));  
     typedef int T;
	//关联失败,对于形式1,类型T和int在字符串形式上并不相同。
//QObject::connect(&ma,SIGNAL(s2(T)),&mb,SLOT(z(int))); 
QObject::connect(&ma,&A::s2,&mb,&B::z1);  //正确,形式3支持隐式类型转换
    	emit ma.s2(2);  //输出z1f
//槽函数与slots
//关联失败,形式1的槽必须使用slots声明。
//QObject::connect(&ma,SIGNAL(s1()),&mb,SLOT(z2()));
    QObject::connect(&ma,&A::s1,&mb,&B::z2);  //正确,形式3的槽不需使用slots声明。
    emit ma.s1();    /*输出x,z2,注意:在之前s1和x的关联并未断开,此时信号s1同时与槽x和z2关联。*/
//访问控制符
    QObject::connect(&ma,SIGNAL(s1()),&mb,SLOT(z3())); //正确,形式1的槽不受访问控制符限制。
    emit ma.s1();  //输出x,z2,z3,因为此时s1与多个槽相关联。
    //QObject::connect(&ma,&A::s1,&mb,&B::z3);//错误,z3是私有的,形式3会受访问控制符的限制。
//函数重载,形式2和形式4的使用见正文
    return 0;		}

作者:黄邦勇帅(原名:黄勇)

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt信号与槽原理 的相关文章

  • 无法初始化静态QList?

    我收到以下错误 Cube cpp 10 error expected initializer before lt lt token 以下是头文件的重要部分 ifndef CUBE H define CUBE H include
  • 将信号/槽(QObject)添加到 QGraphicsItem:性能受到影响?

    我想将信号 槽添加到 QGraphicsItem 以便我可以从另一个线程访问 QGraphicsItemObjects 我知道有两个选项 使用 QGraphicsObject 或从 QObject 和 QGraphicsItem 继承 使用
  • Qt 远程文件浏览器

    我想知道是否有人使用过 Qt 远程文件浏览器 根据我的理解 我有两个选择 当涉及到远程文件时 将 QFileDilaog 与自定义代理模型结合使用 该模型将负责提供远程文件 目录结构 使用自定义对话框 并为本地文件提供标准文件系统模型 为远
  • Qt 信号槽,新符号中的转换类型[重复]

    这个问题在这里已经有答案了 鉴于以下两个 connect ui gt comboBox SIGNAL activated QString ps SLOT requestPlotsAvailable QString connect ui gt
  • 如何在Qt中设置编译器?

    我对 Qt 完全陌生 我下载了离线版本 Qt 5 3 2 for Windows 64 bit VS 2013 OpenGL 573 MB 我无法编译我的项目 I have Qt Creator 3 2 1 开源 基于Qt 5 3 2 MS
  • 我的 QSqlQueryModel 不在列表视图中显示数据

    我正在玩 QSqlQueryModel 但我现在完全陷入困境 我一整天都在寻找解决方案 但到目前为止还没有运气 我所做的工作是它从我的 sqlite 数据库中提取数据 但由于某种原因我无法在列表视图中显示它 我的角色名似乎不存在 对于我从数
  • [本机]:在Qt for Android中使用Java函数和第3方库[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 最近我用qt写了一个android应用程序 但我有一个很大的问题 我可以使用 调用一些原生的android API 比如调用特殊的activit
  • Qt GUI 编程设计

    我正在尝试创建一个 GUI 应用程序 主窗口 一个QMainWindow 包含 9 个固定大小的标签以及主窗口的大小 我尝试在没有 Qt GUI Designer 的情况下以编程方式制作它 该项目构建时没有错误 但我看不到主窗口上显示的任何
  • 调整 QML 图像显示尺寸

    我有一个带有嵌套的 QML 窗口RowLayout 在内排我有两个图像 来源 png这些图像的文件 故意 相当大 当我尝试设置height这些图像上的属性使它们变小 但它们仍然被画得很大 Desired Appearance Actual
  • 如何获取 QIcon 的文件/资源​​路径

    假设我做了这样的事情 QIcon myIcon resources icon ico 我稍后如何确定该图标的路径 例如 QString path myIcon getPath 问题是 没有getPath 会员 我找不到类似的东西 但肯定有办
  • QSpinBox 输入 NaN 作为有效值

    我正在尝试扩展 QSpinBox 以能够输入 NaN 或 nan 作为有效值 根据文档 我应该使用 textFromValue valueFromText 和 validate 函数来完成此操作 但我无法让它工作 因为它仍然不允许我输入除数
  • 使用 cmake 将两种解决方案合二为一

    我有两个单独的 Visual Studio 2013 解决方案 我想将它们迁移到一个解决方案中 因为第一个解决方案 使用 Qt 充当第二个解决方案的 GUI 最后 我希望有一个结构如下的单一解决方案 Solution All Build P
  • (如何)我可以抑制未找到包配置文件的警告吗?

    我正在尝试创建一个CMakeLists txt尝试查找的文件Qt5 如果失败 则尝试回退到Qt4安装 该脚本到目前为止有效 但如果出现以下情况我总会收到警告Qt5未安装 注意FindQt5 cmake是由提供Qt5并且仅当以下情况时才可用Q
  • Qt中如何获取鼠标在屏幕上的位置?

    我想获取屏幕上的鼠标坐标 我怎样才能在 Qt 中做到这一点 在 Windows 上 使用 C 我正在做类似答案中建议的事情对于这个问题 https stackoverflow com q 11737665 1420197 正如文档所述 QC
  • Qt mouseReleaseEvent() 未触发?

    我有一个显示图片的库 我们称之为 PictureGLWidget 其中 class PictureGLWidget public QGLWidget 所以 PictureGLWidget 扩展了 QGLWidget 在PictureGlWi
  • QTextEdit.find() 在 Python 中不起作用

    演示问题的简单代码 usr bin env python import sys from PyQt4 QtCore import QObject SIGNAL from PyQt4 QtGui import QApplication QTe
  • 禁用 QML Slider 的鼠标滚轮

    我希望能够滚动Flickable使用鼠标滚轮 或触摸板上的两根手指 不改变Sliders它可能包含 示例代码及结果应用 import QtQuick 2 7 import QtQuick Window 2 2 import QtQuick
  • 如何使用 Qtimer 添加 1 秒延迟

    我目前有一个方法如下 void SomeMethod int a Delay for one sec timer gt start 1000 After one sec SomeOtherFunction a 这个方法实际上是一个附加到信号
  • 加权 Voronoi 的 CGAL 2D APOLLONIUS 图 - 如何生成和获取面和顶点?

    我正在尝试根据阿波罗尼乌斯图生成加权沃罗诺伊 我正在使用 CGAL 库 我找不到如何从 apollonius 获取面和顶点的好例子 我有以下类型定义 typedef double NT typedef CGAL Cartesian lt N
  • 错误 LNK2001:无法解析的外部符号 __CxxFrameHandler3

    我正在将 Qt 从 VS 2013 迁移到 Qt 5 10 1 到 VS 2015 出现以下多个链接错误 error LNK2001 unresolved external symbol CxxFrameHandler3 error LNK

随机推荐

  • rk3399 Android9.0 ota升级失败

    rk3399 Android9 0 ota升级失败 问题 在rk3399 Android9 0 项目中需要 ota 功能 user版本编译完ota升级包后 在同版本整包升级时遇到如下问题 抓到的logcat内容如下 1044 2343 D
  • 数据安全风险分析及应对策略研究

    报告从理论与实践层面对当前企业面临的内外部数据安全风险进行分析与研究 完成了以下几方面的探索 一是梳理了当前数据安全面临的突出问题 二是提出了数据安全体系建设的行动思路和关键举措 三是提出了数据安全建设发展建议 关注公众号 互联互通社区 回
  • angular自动化测试--protractor

    前戏 面向模型编程 测试驱动开发 先保障交互逻辑 再调整细节 by 雪狼 为什么要自动化测试 1 提高产出质量 2 减少重构时的痛 反正我最近重构多了 痛苦经历多了 3 便于新人接手 angular自动化测试主要分 端到端测试和单元测试 很
  • 专访戴文渊:第四范式(现在)是一家怎样的公司?

    李根 发自 凹非寺 量子位 报道 公众号 QbitAI 第四范式创始人及CEO戴文渊 第四范式是一家备受关注的公司 仅创始团队成员来看 哪一个不是计算机 机器学习领域响当当的名字 戴文渊是ACM2005全球冠军 百度机器学习系统带队打造者
  • RecyclerView中item布局的"match_parent"属性失效--LayoutInflate的深入了解

    用recyclerview 给item布局使用了match parent属性 运行后不起作用 查了下 是在onCreateViewHolder中加载布局时候出了问题 一开始用的View Inflate方法 查看源码后 发现View infl
  • Java学生个人信息录入

    编写 Java 程序显示学生的个人信息 定义类Student 该类中应该有三个私有属性 姓名 name 年龄 age 性别 sex 输入 第一行为一个数 表示录入学生个数 第二行依次为学生姓名 年龄 性别 最后一行输入一个学生的姓名 输出
  • 【selenium】python+selenium+unittest,关于每次执行完一个测试用例都关闭浏览器等时间较长的问题之解决方案...

    我一直在思考第一个博客应该写什么 然后我就解决了开通博客后解决的第一个问题 择题不如撞题 如果大多数人和我一样 接触python selenium unittest是从selenium IDE开始的话 你也一定会遇到这样的问题 我们写了5个
  • 论文阅读_大模型_ToolLLM

    英文名称 ToolLLM Facilitating Large Language Models to Master 16000 Real world APIs 中文名称 TOOLLLM 帮助大语言模型掌握16000多个真实世界的API 文章
  • telnet出现Connection closed by foreign host

    2018 10 26 执行命令 telnet smtp exmail qq com 465 出现信息 root pengman Desktop telnet 10 223 30 128 7027 Tring 10 223 30 128 70
  • 50 道 Java 基础编程练习题

    https gold xitu io post 58a4276f61ff4b006c899609
  • CMake 入门实战(精)

    http www hahack com codes cmake 从实例入手 讲解 CMake 的常见用法 Contents 什么是 CMake 入门案例 单个源文件 多个源文件 自定义编译选项 安装和测试 支持 gdb 添加环境检查 添加版
  • Java/JDK 21正式发布!15个特性一览

    订阅专栏 JDK 21已经于2023年9月19日正式发布 本文总结了JDK 21发布的新特性 发布版本说明 根据发布的规划 这次发布的 JDK 21 将是一个长期支持版 LTS 版 LTS 版每 2 年发布一个 上一次长期支持版是 21 年
  • s24服务器维护时长,服务器维护:艾锑人告诉您Mbps和mb/s换算知识

    影响我们一生百倍差距的四大效应 观察者效应 你的世界是什么样是由你的观察决定的 这个效应是在 潜能突破 研习营课堂上发现的 我们有个练习叫三生万物 每个人都会成为一次观察者角色 当大家在成为其他角色时 他们总是发现不了自己的问题 无论我们怎
  • 7.opencv——边缘检测( 拉普拉斯(Laplacian),Sobel,Canny边缘检测)

    边缘检测 边缘检测 拉普拉斯 Laplacian 边缘检测 Sobel边缘检测 Canny边缘检测 拉普拉斯 Laplacian Sobel Canny对比 边缘检测 qquad 各类图像中 由于不同物体对电磁波的反射特性不同 在物体与背景
  • Windows中使用GCC介绍

    Windows中使用GCC介绍 GCC介绍 GCC是由许多组件组成的 GCC原名为GNU C语言编译器 GNU C Compiler 只能处理C语言 但其很快扩展 变得可处理C 后来又扩展为能够支持更多编程语言 如Fortran Pasca
  • display:inline-block元素之间空隙的产生原因和解决办法

    display inline block是一种布局方法 它相比于与浮动 定位最大的不同就是其没有父元素的匿名包裹特性 这使得display inline block属性的使用非常自由 可与文字 图片混排 可内嵌block属性元素 可以置身于
  • h2事务与mysql_mysql、h2插入性能对比

    2013 01 05 更新 导致循环调用save插入慢的问题是我循环调用了service方法 而不是在service内部循环 而事物是在service级别 所以相当于每次插入都提交事物 所以慢了 同样是插入 差别咋就这大呢 操作系统 wub
  • 【WPF动画】实现从鼠标点击中心开始的波纹扩散特效

    效果图 实现原理 Storyboard组合动画实现 核心代码 1 获取点击区域 确定扩散圆形辐射范围等属性 var ellipse new Ellipse Width 10 Height 10 Fill Brushes LightBlue
  • ASP.NET的优点

    ASP NET 是一个统一的 Web 开发平台 它提供开发人员创建企业级 Web 应用程序所需的服务 尽管 ASP NET 的语法基本上与 ASP 兼容 但是它还提供了一个新的编程模型和基础结构以提高应用程序的安全性 缩放性和稳定性 通过逐
  • Qt信号与槽原理

    Qt信号与槽原理 本文为原创文章 转载请注明出处 或注明转载自 黄邦勇帅 原名 黄勇 本文出自本人原创著作 Qt5 10 GUI完全参考手册 网盘地址 https pan baidu com s 1iqagt4SEC8PUYx6t3ku39