当前位置: 首页 > news >正文

QT:【第一个QT程序】【信号和槽】

目录

一. 第一个QT程序

1.1纯代码实现

1.2可视化操作实现

1.3 项目文件解析

1.3.1 .pro文件解析

1.3.2 widget.h 文件解析

1.3.3 main.cpp文件解析

1.3.4 widget.cpp

1.3.5 widget.ui文件解析

1.4对象树

演示自动释放的过程

1.5 中文乱码

1.6 Qt窗口坐标系

二. 信号和槽

2.1 信号和槽的概念

2.2 信号和槽的使用

2.2.1 连接信号和槽

2.2.2 查看信号和槽

2.2.3 通过 Qt Creator生成信号槽代码

2.3 自定义信号和槽

2.3.1 基本语法

2.3.2 带参数的信号和槽

2.4其他说明

2.4.1 信号和槽的断开

2.4.2使用lambda定义槽函数

2.5 信号与槽的优缺点


一. 第一个QT程序

1.1纯代码实现

QString是什么?以前学习字符串的时候,在C语言中是以\0为结尾,C++中string类型标识字符串。很久之前,Qt诞生于1991年,当时的这些容器都不太好用,这里Qt就独自的实现了一系列的基础类,包括QString,QVector。。。当然现在是比较成熟了。都可以用

1.2可视化操作实现

(1)双击:"widget.ui"文件;

2)拖拽控件至ui 界面窗口并修改内容;

(3)构建并运行,效果如下所示:

在这个过程中,qmake在编译项目的时候,基于.ui里面的内容自动的生成一段C++代码,通过这个C++代码就能构建出内容了:

就是下面的.h文件:

里面其实就是创建一个label对象什么的:

1.3 项目文件解析

1.3.1 .pro文件解析

工程新建好之后,在工程目录列表中会有一个后缀为".pro"的文件。".pro"文件即工程文件(project),它是qmake自动生成的、用于生成makefile的配置文件。

进入之后:

".pro"文件的写法如下:

1. 注释:从"#"开始,到这一行结束。

2. QT += core gui //Qt包含的模块 Qt5包含的模块如下图所示:

3. greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 这条语句的含义是,如果 QT_MAJOR_VERSION 大于 4(也就是当前使用的 Qt5 及更高版本),需要增加 widgets 模块。如果项目仅需支持 Qt5,也可以直接添加"QT += widgets"一句。不过为了保持代码兼容,最好还是按照 QtCreator 生成的语句编写。

4. 指定生成的应用程序名:TARGET = QtDemo 5. TEMPLATE = app //模板。告诉 qmake 为这个应用程序生成哪种 makefile。下面是可供选择的模板:

⚫ app:建立一个应用程序的 makefile。这是默认值,所以如果模板没有被指定,这个将被使用。

⚫ lib:建立一个库的 makefile。

⚫ vcapp:建立一个应用程序的 VisualStudio 项目文件。

⚫ vclib:建立一个库的 VisualStudio 项目文件。

⚫ subdirs:这是一个特殊的模板,它可以创建一个能够进入特定目录的 makefile 并且为它调用 make 的 makefile。

6. 工程中包含的源文件:SOURCES += main.cpp/widget.cpp

7. 工程中包含的头文件:HEADERS += widget.h

8. 工程中包含的资源文件:RESOURCES += painter.qrc

9. 工程中包含的"ui"设计文件:FORMS += widget.ui

10. 配置信息:CONFIG += c++11 (使用 c++11 的特性) CONFIG 用来告诉 qmake 关于应用程序的配置信息。

1.3.2 widget.h 文件解析

在Qt中,如果要使用信号与槽(signal和slot)的机制,就必须加入Q_OBJECT宏; Ui::Widget *ui; 这个指针是用前面声明的namespace Ui里的Widget类定义的,所以指针ui是指向可视化设计的界面,后面要访问界面上的组件,都需要通过这个指针ui去访问。

1.3.3 main.cpp文件解析

1. Qt系统提供的标准类名声明头文件没有.h后缀;

2. Qt一个类对应一个头文件,类名就是头文件名;

3. QApplication为应用程序类;QApplication a;(a为应用程序对象,有且仅有一个。)

⚫ QApplication管理图形用户界面应用程序的控制流和主要设置。

⚫ QApplication是Qt的整个后台管理的命脉。它包含主事件循环,在其中来自窗口系统和其它资源的所有事件处理和调度。它也处理应用程序的初始化和结束,并且提供对话管理。

⚫ 对于任何一个使用Qt的图形用户界面应用程序,都正好存在一个QApplication对象,而不论这个应用程序在同一时间内是不是有0、1、2或更多个窗口。

4. myWidget w; //实例化窗口对象

5. w.show();//调用show函数显示窗口

6. a.exec():程序进入消息循环,等待对用户输入进行响应。这里main()把控制权转交给Qt,Qt完成事件处理工作,当应用程序退出的时候exec()的值就会返回。在exec()中,Qt接受并处理用户和系统的事件并且把它们传递给适当的窗口部件。

1.3.4 widget.cpp

1.3.5 widget.ui文件解析

widget.ui 是窗体界面定义文件,是一个XML文件,定义了窗口上的所有组件的属性设置、布局,及其信号与槽函数的关联等。用UI设计器可视化设计的界面都由Qt自动解析,并以XML文件的形式保存下来。在设计界面时,只需在UI设计器里进行可视化设计即可,而不用管widget.ui文件是怎么生成的。

1.4对象树

在1.1写的那个代码,我是没有释放的,会导致内存泄漏吗?不会的

如果我不去new呢?在栈上创建,不显示hello world?此时的label对象随着构造函数的结束就销毁了。

所以把label对象交给对象树是最合理的。

演示自动释放的过程

重新创建一个项目,并创建新的class

这里就会多出来两个:

这里的目的就是在析构函数中我们要看到的确是被析构了,这里在主函数调用之后:

被打印出来就说明析构函数确实的执行了,虽然没有显示的delete,但是挂到了对象树中,窗口被销毁的时候,就会自动的销毁所有的对象。

1.5 中文乱码

这里使用qDebug代替cout

cout对编码的处理不太好,这里在qDebug内部直接就帮我们调试好了。

1.6 Qt窗口坐标系

坐标体系:以左上角为原点(0,0),X向右增加,Y向下增加。

对于嵌套窗口,其坐标是相对于父窗口来说的。

示例:使用Qt中的坐标系设置控件的位置;

二. 信号和槽

2.1 信号和槽的概念

在 Qt 中,用户和控件的每次交互过程称为一个事件。比如 "用户点击按钮" 是一个事件,"用户关闭窗口" 也是一个事件。每个事件都会发出一个信号,例如用户点击按钮会发出 "按钮被点击" 的信号,用户关闭窗口会发出 "窗口被关闭" 的信号。

Qt 中的所有控件都具有接收信号的能力,一个控件还可以接收多个不同的信号。对于接收到的每个信号,控件都会做出相应的响应动作。例如,按钮所在的窗口接收到 "按钮被点击" 的信号后,会做出 "关闭自己" 的响应动作;再比如输入框自己接收到 "输入框被点击" 的信号后,会做出 "显示闪烁的光标,等待用户输入数据" 的响应动作。在 Qt 中,对信号做出的响应动作就称之为槽。

信号和槽是 Qt 特有的消息传输机制,它能将相互独立的控件关联起来。比如,"按钮" 和 "窗口" 本身是两个独立的控件,点击 "按钮" 并不会对 "窗口" 造成任何影响。通过信号和槽机制,可以将 "按钮" 和 "窗口" 关联起来,实现 "点击按钮会使窗口关闭" 的效果。

信号是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时 Qt 对应的窗口类会发出某个信号,以此对用户的操作做出反应。因此,信号的本质就是事件。如:

・按钮单击、双击・窗口刷新
・鼠标移动、鼠标按下、鼠标释放
・键盘输入


那么在 Qt 中信号是通过什么形式呈现给使用者的呢?

・我们对哪个窗口进行操作,哪个窗口就可以捕捉到这些被触发的事件。
・对于使用者来说触发了一个事件我们就可以得到 Qt 框架给我们发出的某个特定信号。
・信号的呈现形式就是函数,也就是说某个事件产生了,Qt 框架就会调用某个对应的信号函数,通知使用者。
在 Qt 中信号的发出者是某个实例化的类对象。

槽的本质

槽(Slot)就是对信号响应的函数。槽就是一个函数,与一般的 C++ 函数是一样的,可以定义在类的任何位置(public、protected 或 private),可以具有任何参数,可以被重载,也可以被直接调用(但是不能有默认参数)。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。

说明
(1)信号和槽机制底层是通过函数间的相互调用实现的。每个信号都可以用函数来表示,称为信号函数;每个槽也可以用函数表示,称为槽函数。例如:"按钮被按下" 这个信号可以用 clicked () 函数表示,"窗口关闭" 这个槽可以用 close () 函数表示,假如使用信号和槽机制实现:"点击按钮会关闭窗口" 的功能,其实就是 clicked () 函数调用 close () 函数的效果。
(2)信号函数和槽函数通常位于某个类中,和普通的成员函数相比,它们的特别之处在于:
・信号函数用 signals 关键字修饰,槽函数用 public slots、protected slots 或者 private slots 修饰。signals 和 slots 是 Qt 在 C++ 的基础上扩展的关键字,专门用来指明信号函数和槽函数;
・信号函数只需要声明,不需要定义(实现),而槽函数需要定义(实现)。

信号函数的定义是 Qt 自动在编译程序之前生成的。编写 Qt 应用程序的程序员无需关注。

这种自动生成代码的机制称为元编程(Meta Programming)。这种操作在很多场景中都能见到。

2.2 信号和槽的使用

2.2.1 连接信号和槽

在 Qt 中,QObject 类提供了一个静态成员函数 connect() ,该函数专门用来关联指定的信号函数和槽 函数。

关于 QObject
QObject 是 Qt 内置的父类。Qt 中提供的很多类都是直接或者间接继承自 QObject。

这一点的设定和 Java 是非常相似的。

简单的使用代码

点击就会关闭

这里就需要注意一个东西了,第二个和第三个参数是const char*类型,但是我们传的都是函数指针类型,这在C++中肯定是不行的。在原来的QT肯定是不行的,需要传入宏对函数指针做解析,转换成const char*类型:

connect(button,SIGNAL(&QPushButton::clicked),this,SLOT(&Widget::close));

Qt5开始就对这种写法做了简化,给connect提供了重载版本,第二个第四个参数成为了泛型,允许传入任意指针的类型了。

2.2.2 查看信号和槽

系统自带的信号和槽通常是通过 “Qt 帮助文档” 来查询。

如上述示例,要查询 “按钮” 的信号,在帮助文档中输入:QPushButton,

  • 首先可以在 “Contents” 中寻找关键字 signals,
  • 如果没有找到,继续去父类中查找。因此我们去它的父类 QAbstractButton 中继续查找关键字 signals。

这里的clicked()就是要找的信号。槽函数的寻找方式和信号一样,只不过它的关键字是slot。

2.2.3 通过 Qt Creator生成信号槽代码

在 UI 设计窗口中拖入一个 "按钮" ,并且修改 "按钮" 的名称及字体大小等;

可视化生成槽函数:

当单击 "转到槽..." 之后,出现如下界面:对于按钮来说,当点击时发送的信号是:clicked (),所以此处选择:clicked ()

在"widget.h"头文件中自动添加槽函数的声明;

在"widget.cpp"中自动生成槽函数定义.

在槽函数函数定义中添加要实现的功能.实现关闭窗口的效果.

注意如果用这种方式的话,是不需要去显示的connect的,可以根据名字on_pushButton_clicked就可以直接关联号新号和槽了,因为pushButton是名字,clicked是信号(可以根据名字搜索),这个函数本身就是槽

2.3 自定义信号和槽

2.3.1 基本语法

在 Qt 中,允许自定义信号的发送方以及接收方,即可以自定义信号函数和槽函数。但是对于自定义的信号函数和槽函数有一定的书写规范。

1、自定义信号函数书写规范
(1)自定义信号函数必须写到 "signals" 下;
(2)返回值为 void,只需要声明,不需要实现
(3)可以有参数,也可以发生重载;

2、自定义槽函数书写规范
(1)早期的 Qt 版本要求槽函数必须写到 "public slots" 下,但是现在高级版本的 Qt 允许写到类的 "public" 作用域中或者全局下;
(2)返回值为 void,需要声明,也需要实现
(3)可以有参数,可以发生重载;

3、发送信号
使用 "emit" 关键字发送信号。"emit" 是一个空的宏。"emit" 其实是可选的,没有什么含义,只是为了提醒开发人员。

Widget.h中:

Widget.cpp中,注意要使用emit发送信号:

这里的标题也就变了:

还可以利用ui来创建一个按钮,用点击按钮的信号来发送我们自己的信号:

可以通过名字on_pushButton_clicked自动建立connect,不用我们去connect:

点击之后:

2.3.2 带参数的信号和槽

Qt 的信号和槽也支持带有参数,同时也可以支持重载。

此处我们要求,信号函数的参数列表要和对应连接的槽函数参数列表一致。

此时信号触发,调用到槽函数的时候,信号函数中的实参就能够被传递到槽函数的形参当中。

通过这样的机制,就可以让信号给槽传递数据了

槽函数实现:

2.4其他说明

2.4.1 信号和槽的断开

ui中创建两个按钮,一个按钮专门负责断开另一个按钮的连接:

        注意如果不去disconnect的话,这里的信号就会绑定两个槽,都会执行。

2.4.2使用lambda定义槽函数

button是new出来的对象,直到窗口关闭才会释放。

2.5 信号与槽的优缺点

优点:松散耦合
信号发送者不需要知道发出的信号被哪个对象的槽函数接收,槽函数也不需要知道哪些信号关联了自己,Qt 的信号槽机制保证了信号与槽函数的调用。支持信号槽机制的类或者父类必须继承于 QObject 类。

缺点:效率较低
与回调函数相比,信号和槽稍微慢一些,因为它们提供了更高的灵活性,尽管在实际应用程序中差别不大。通过信号调用的槽函数比直接调用的速度慢约 10 倍(这是定位信号的接收对象所需的开销;遍历所有关联;编组 / 解组传递的参数;多线程时,信号可能需要排队),这种调用速度对性能要求不是非常高的场景是可以忽略的,是可以满足绝大部分场景。

http://www.dtcms.com/a/355276.html

相关文章:

  • 使用uni-app和Canvas生成简易双列表格布局并长按下载到本地
  • 混淆 打包 编译
  • Ovis2.5技术解密:原生分辨率与“反思模式”如何铸就新一代MLLM王者
  • 2024年山东省信息学小学组(CSP-X)第一轮题解
  • 冒泡排序算法详解(python code)
  • Python训练营打卡 DAY 50 预训练模型+CBAM模块
  • Shell 编程基础与实践要点梳理
  • PCIe 5.0 SSD连续读写缓存用完速度会骤降吗?
  • IntelliJ IDEA 反编译JAR包记录
  • Beats与Elasticsearch高效数据采集指南
  • Komo Searc-AI驱动的搜索引擎
  • 控制系统仿真之PID校正1-系统固有属性(四)
  • 【ai编辑器】使用cursor-vip获得cursor的pro版 pro plan(mac)
  • 【C语言16天强化训练】从基础入门到进阶:Day 13
  • 模拟实现Linux中的进度条
  • 带动态条件的模糊查询SQL
  • 【Linux基础知识系列:第一百一十四篇】使用lsof查看打开的文件
  • frp 一个高性能的反向代理服务
  • VMware + Ubuntu 桥接模式不能联网 的常见原因、排查思路和解决步骤
  • element-plus的el-scrollbar显示横向滚动条
  • 整体设计 修订 之1 三“先”之“基” 与范畴重构:康德先验哲学的批判性程序化实现
  • 电商高并发稳赢指南:ZKmall开源商城微服务架构的实战拆解
  • AI视觉重塑汽车质检,四大车间全景解析
  • Android15 GKI版本分析Kernel Crash问题
  • 金属超声波风速风向多参数一体传感器
  • NFT:Web3数字新资产
  • k230 使用摄像头将拍照的RGB565格式图片,保存为jpg图片文件到板载TF存储卡中
  • flutter 中 的 关键字
  • flutter Function和自定义的Callback有什么区别?
  • flutter 高斯模糊闪烁问题