QT中的信号与槽的概念体制

2024-04-12 03:18
文章标签 qt 概念 信号 体制

本文主要是介绍QT中的信号与槽的概念体制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

信号与槽作为 QT 的核心机制在 QT编程 中有着广泛的应用,本文介绍了信号与槽的一些基本概念、元对象工具以及在实际使用过程中应注意的一些问题。 
QT 是一个跨平台的 C++ GUI 应用构架,它提供了丰富的窗口部件集,具有面向对象、易于扩展、真正的组件 编程 等特点,更为引人注目的是目前 Linux 上最为流行的 KDE 桌面环境就是建立在 QT 库的基础之上。 QT 支持下列平台: MS/WINDOWS-95 、 98、 NT 和 2000 ; UNIX/X11-linux 、 Sun Solaris 、 HP-UX 、 Digital Unix 、 IBM AIX 、 SGI IRIX ; EMBEDDED- 支持framebuffer 的 Linux 平台。伴随着 KDE 的快速发展和普及, QT 很可能成为 Linux 窗口平台上进行软件开发时的 GUI 首选。 

一、概述 

信号和槽机制是 QT 的核心机制,要精通 QT编程 就必须对信号和槽有所了解。信号和槽是一种高级接口,应用于对象之间的通信,它是 QT 的核心特性,也是 QT 区别于其它工具包的重要地方。信号和槽是 QT 自行定义的一种通信机制,它独立于标准的C/C++ 语言,因此要正确的处理信号和槽,必须借助一个称为 moc ( Meta Object Compiler )的 QT 工具,该工具是一个 C++ 预处理程序,它为高层次的事件处理 自动 生成所需要的附加代码。 

在我们所熟知的很多 GUI 工具包中,窗口小部件 (widget) 都有一个回调函数用于响应它们能触发的每个动作,这个回调函数通常是一个指向某个函数的指针。但是,在 QT 中信号和槽取代了这些凌乱的函数指针,使得我们编写这些通信程序更为简洁明了。信号和槽能携带任意数量和任意类型的参数,他们是类型完全安全的,不会像回调函数那样产生 core dumps 。 

所有从 QObject 或其子类 ( 例如 Qwidget) 派生的类都能够包含信号和槽。当对象改变其状态时,信号就由该对象发射 (emit) 出去,这就是对象所要做的全部事情,它不知道另一端是谁在接收这个信号。这就是真正的信息封装,它确保对象被当作一个真正的软件组件来使用。槽用于接收信号,但它们是普通的对象成员函数。一个槽并不知道是否有任何信号与自己相连接。而且,对象并不了解具体的通信机制。 

你可以将很多信号与单个的槽进行连接,也可以将单个的信号与很多的槽进行连接,甚至于将一个信号与另外一个信号相连接也是可能的,这时无论第一个信号什么时候发射系统都将立刻发射第二个信号。总之,信号与槽构造了一个强大的部件 编程 机制。 

二、信号 

当某个信号对其客户或所有者发生的内部状态发生改变,信号被一个对象发射。只有定义过这个信号的类及其派生类能够发射这个信号。当一个信号被发射时,与其相关联的槽将被立刻执行,就象一个正常的函数调用一样。信号 - 槽机制完全独立于任何 GUI 事件循环。只有当所有的槽返回以后发射函数( emit )才返回。如果存在多个槽与某个信号相关联,那么,当这个信号被发射时,这些槽将会一个接一个地执行,但是它们执行的顺序将会是随机的、不确定的,我们不能人为地指定哪个先执行、哪个后执行。 

信号的声明是在头文件中进行的, QT 的 signals 关键字指出进入了信号声明区,随后即可声明自己的信号。例如,下面定义了三个信号: 

signals: 
void mySignal(); 
void mySignal(int x); 
void mySignalParam(int x,int y); 



在上面的定义中, signals 是 QT 的关键字,而非 C/C++ 的。接下来的一行 void mySignal() 定义了信号 mySignal ,这个信号没有携带参数;接下来的一行 void mySignal(int x) 定义了重名信号 mySignal ,但是它携带一个整形参数,这有点类似于 C++ 中的虚函数。从形式上讲信号的声明与普通的 C++ 函数是一样的,但是信号却没有函数体定义,另外,信号的返回类型都是 void ,不要指望能从信号返回什么有用信息。 

信号由 moc自动 产生,它们不应该在 .cpp 文件中实现。 

三、槽 

槽是普通的 C++ 成员函数,可以被正常调用,它们唯一的特殊性就是很多信号可以与其相关联。当与其关联的信号被发射时,这个槽就会被调用。槽可以有参数,但槽的参数不能有缺省值。 

既然槽是普通的成员函数,因此与其它的函数一样,它们也有存取权限。槽的存取权限决定了谁能够与其相关联。同普通的 C++ 成员函数一样,槽函数也分为三种类型,即 public slots 、 private slots 和 protected slots 。 

public slots :在这个区内声明的槽意味着任何对象都可将信号与之相连接。这对于组件 编程 非常有用,你可以创建彼此互不了解的对象,将它们的信号与槽进行连接以便信息能够正确的传递。 
protected slots :在这个区内声明的槽意味着当前类及其子类可以将信号与之相连接。这适用于那些槽,它们是类实现的一部分,但是其界面接口却面向外部。 
private slots :在这个区内声明的槽意味着只有类自己可以将信号与之相连接。这适用于联系非常紧密的类。 
槽也能够声明为虚函数,这也是非常有用的。 

槽的声明也是在头文件中进行的。例如,下面声明了三个槽: 

public slots: 
void mySlot(); 
void mySlot(int x); 
void mySignalParam(int x,int y); 



四、信号与槽的关联 

通过调用 QObject 对象的 connect 函数来将某个对象的信号与另外一个对象的槽函数相关联,这样当发射者发射信号时,接收者的槽函数将被调用。该函数的定义如下: 

bool QObject::connect ( const QObject * sender, const char * signal, 
const QObject * receiver, const char * member ) [static] 



这个函数的作用就是将发射者 sender 对象中的信号 signal 与接收者 receiver 中的 member 槽函数联系起来。当指定信号 signal 时必须使用 QT 的宏 SIGNAL() ,当指定槽函数时必须使用宏 SLOT() 。如果发射者与接收者属于同一个对象的话,那么在 connect 调用中接收者参数可以省略。 

例如,下面定义了两个对象:标签对象 label 和滚动条对象 scroll ,并将 valueChanged() 信号与标签对象的 setNum() 相关联,另外信号还携带了一个整形参数,这样标签总是显示滚动条所处位置的值。 

QLabel *label = new QLabel; 
QScrollBar *scroll = new QScrollBar; 
QObject::connect( scroll, SIGNAL(valueChanged(int)), 
label, SLOT(setNum(int)) ); 



一个信号甚至能够与另一个信号相关联,看下面的例子: 

class MyWidget : public QWidget 

public: 
MyWidget(); 
... 
signals: 
void aSignal(); 
... 
private: 
... 
QPushButton *aButton; 
}; 

MyWidget::MyWidget() 

aButton = new QPushButton( this ); 
connect( aButton, SIGNAL(clicked()), SIGNAL(aSignal()) ); 




在上面的构造函数中, MyWidget 创建了一个私有的按钮 aButton ,按钮的单击事件产生的信号 clicked() 与另外一个信号 aSignal()进行了关联。这样一来,当信号 clicked() 被发射时,信号 aSignal() 也接着被发射。当然,你也可以直接将单击事件与某个私有的槽函数相关联,然后在槽中发射 aSignal() 信号,这样的话似乎有点多余。 

当信号与槽没有必要继续保持关联时,我们可以使用 disconnect 函数来断开连接。其定义如下: 

bool QObject::disconnect ( const QObject * sender, const char * signal, 
const Object * receiver, const char * member ) [static] 



这个函数断开发射者中的信号与接收者中的槽函数之间的关联。 

有三种情况必须使用 disconnect() 函数:
 

断开与某个对象相关联的任何对象。这似乎有点不可理解,事实上,当我们在某个对象中定义了一个或者多个信号,这些信号与另外若干个对象中的槽相关联,如果我们要切断这些关联的话,就可以利用这个方法,非常之简洁。 

disconnect( myObject, 0, 0, 0 ) 
或者 
myObject->disconnect() 



断开与某个特定信号的任何关联。 

disconnect( myObject, SIGNAL(mySignal()), 0, 0 ) 
或者 
myObject->disconnect( SIGNAL(mySignal()) ) 



断开两个对象之间的关联。 

disconnect( myObject, 0, myReceiver, 0 ) 
或者 
myObject->disconnect( myReceiver ) 



在 disconnect 函数中 0 可以用作一个通配符,分别表示任何信号、任何接收对象、接收对象中的任何槽函数。但是发射者 sender 不能为 0 ,其它三个参数的值可以等于 0 。 

五、元对象工具 

元对象编译器 moc ( meta object compiler )对 C++ 文件中的类声明进行分析并产生用于初始化元对象的 C++ 代码,元对象包含全部信号和槽的名字以及指向这些函数的指针。 

moc 读 C++ 源文件,如果发现有 Q_OBJECT 宏声明的类,它就会生成另外一个 C++ 源文件,这个新生成的文件中包含有该类的元对象代码。例如,假设我们有一个头文件 mysignal.h ,在这个文件中包含有信号或槽的声明,那么在编译之前 moc 工具就会根据该文件 自动 生成一个名为 mysignal.moc.h 的 C++ 源文件并将其提交给编译器;类似地,对应于 mysignal.cpp 文件 moc 工具将 自动生成一个名为 mysignal.moc.cpp 文件提交给编译器。 

元对象代码是 signal/slot 机制所必须的。用 moc 产生的 C++ 源文件必须与类实现一起进行编译和连接,或者用 #include 语句将其包含到类的源文件中。 moc 并不扩展 #include 或者 #define 宏定义 , 它只是简单的跳过所遇到的任何预处理指令。 

六、程序样例 

这里给出了一个简单的样例程序,程序中定义了三个信号、三个槽函数,然后将信号与槽进行了关联,每个槽函数只是简单的弹出一个对话框窗口。读者可以用 kdevelop 生成一个简单的 QT 应用程序,然后将下面的代码添加到相应的程序中去。 

信号和槽函数的声明一般位于头文件中,同时在类声明的开始位置必须加上 Q_OBJECT 语句,这条语句是不可缺少的,它将告诉编译器在编译之前必须先应用 moc 工具进行扩展。关键字 signals 指出随后开始信号的声明,这里 signals 用的是复数形式而非单数,siganls 没有 public 、 private 、 protected 等属性,这点不同于 slots 。另外, signals 、 slots 关键字是 QT 自己定义的,不是 C++中的关键字。 

信号的声明类似于函数的声明而非变量的声明,左边要有类型,右边要有括号,如果要向槽中传递参数的话,在括号中指定每个形式参数的类型,当然,形式参数的个数可以多于一个。 

关键字 slots 指出随后开始槽的声明,这里 slots 用的也是复数形式。 

槽的声明与普通函数的声明一样,可以携带零或多个形式参数。既然信号的声明类似于普通 C++ 函数的声明,那么,信号也可采用C++ 中虚函数的形式进行声明,即同名但参数不同。例如,第一次定义的 void mySignal() 没有带参数,而第二次定义的却带有参数,从这里我们可以看到 QT 的信号机制是非常灵活的。 

信号与槽之间的联系必须事先用 connect 函数进行指定。如果要断开二者之间的联系,可以使用函数 disconnect 。 

//tsignal.h 
... 
class TsignalApp:public QMainWindow 

Q_OBJECT 
... 
// 信号声明区 
signals: 
// 声明信号 mySignal() 
void mySignal(); 
// 声明信号 mySignal(int) 
void mySignal(int x); 
// 声明信号 mySignalParam(int,int) 
void mySignalParam(int x,int y);



http://blog.csdn.net/xiaoyangger/article/details/8616910

这篇关于QT中的信号与槽的概念体制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/895954

相关文章

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo

【QT】基础入门学习

文章目录 浅析Qt应用程序的主函数使用qDebug()函数常用快捷键Qt 编码风格信号槽连接模型实现方案 信号和槽的工作机制Qt对象树机制 浅析Qt应用程序的主函数 #include "mywindow.h"#include <QApplication>// 程序的入口int main(int argc, char *argv[]){// argc是命令行参数个数,argv是

【MRI基础】TR 和 TE 时间概念

重复时间 (TR) 磁共振成像 (MRI) 中的 TR(重复时间,repetition time)是施加于同一切片的连续脉冲序列之间的时间间隔。具体而言,TR 是施加一个 RF(射频)脉冲与施加下一个 RF 脉冲之间的持续时间。TR 以毫秒 (ms) 为单位,主要控制后续脉冲之前的纵向弛豫程度(T1 弛豫),使其成为显著影响 MRI 中的图像对比度和信号特性的重要参数。 回声时间 (TE)

Python QT实现A-star寻路算法

目录 1、界面使用方法 2、注意事项 3、补充说明 用Qt5搭建一个图形化测试寻路算法的测试环境。 1、界面使用方法 设定起点: 鼠标左键双击,设定红色的起点。左键双击设定起点,用红色标记。 设定终点: 鼠标右键双击,设定蓝色的终点。右键双击设定终点,用蓝色标记。 设置障碍点: 鼠标左键或者右键按着不放,拖动可以设置黑色的障碍点。按住左键或右键并拖动,设置一系列黑色障碍点

使用Qt编程QtNetwork无法使用

使用 VS 构建 Qt 项目时 QtNetwork 无法使用的问题 - 摘叶飞镖 - 博客园 (cnblogs.com) 另外,强烈建议在使用QNetworkAccessManager之前看看这篇文章: Qt 之 QNetworkAccessManager踏坑记录-CSDN博客 C++ Qt开发:QNetworkAccessManager网络接口组件 阅读目录 1.1 通用API函数

计算机网络基础概念 交换机、路由器、网关、TBOX

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、VLAN是什么?二 、交换机三、路由器四、网关五、TBOXTelematics BOX,简称车载T-BOX,车联网系统包含四部分,主机、车载T-BOX、手机APP及后台系统。主机主要用于车内的影音娱乐,以及车辆信息显示;车载T-BOX主要用于和后台系统/手机APP通信,实现手机APP的车辆信息显示与控

列举你能想到的UNIX信号,并说明信号用途

信号是一种软中断,是一种处理异步事件的方法。一般来说,操作系统都支持许多信号。尤其是UNIX,比较重要应用程序一般都会处理信号。 UNIX定义了许多信号,比如SIGINT表示中断字符信号,也就是Ctrl+C的信号,SIGBUS表示硬件故障的信号;SIGCHLD表示子进程状态改变信号;SIGKILL表示终止程序运行的信号,等等。信号量编程是UNIX下非常重要的一种技术。 Unix信号量也可以

Qt多语种开发教程

Qt作为跨平台的开发工具,早已应用到各行各业的软件开发中。 今天讲讲,Qt开发的正序怎么做多语言开发。就是说,你设置中文,就中文显示;设置英语就英文显示,设置繁体就繁体显示,设置发育就显示法语等。 开发环境(其实多语种这块根环境没太大关系):win10,Qt.5.12.10 一.先用QtCreator创建一个简单的桌面程序 1.工程就随便命名“LanguageTest”,其他默认。 2.在设计师

01 Docker概念和部署

目录 1.1 Docker 概述 1.1.1 Docker 的优势 1.1.2 镜像 1.1.3 容器 1.1.4 仓库 1.2 安装 Docker 1.2.1 配置和安装依赖环境 1.3镜像操作 1.3.1 搜索镜像 1.3.2 获取镜像 1.3.3 查看镜像 1.3.4 给镜像重命名 1.3.5 存储,载入镜像和删除镜像 1.4 Doecker容器操作 1.4