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

【Qt--从入门到精通】什么是Qt?如何使用Qt创建一个简单的项目

目录

一、Qt背景介绍

1.1 QT是什么?

1.2 QT的发展史

1.3 Qt的优点

二、Qt HelloWorld程序

通过可视化操作实现

通过代码实现

三、项目文件解析

3.1 .pro文件

3.2 Widget.h文件

3.3 main文件解析

3.4 Widget.cpp文件

3.5 Widget.ui文件

四、查看帮助文档

五、对象树


一、Qt背景介绍

1.1 QT是什么?

        Qt是⼀个跨平台的C++图形用户界面应用程序框架。它为应用程序开发者提供了建立艺术级图形界面所需的所有功能。它是完全面向对象的,很容易扩展。Qt为开发者提供了⼀种基于组件的开发模式,开发者可以通过简单的拖拽和组合来实现复杂的应⽤程序,同时也可以使用C++语言进行高级开发。

1.2 QT的发展史
1991 年 Qt 最早由奇趣科技开发;
1996 年 进⼊商业领域,它也是目前流行的 Linux 桌面环境 KDE 的基础;
2008 年 奇趣科技被诺基亚公司收购,Qt 成为诺基亚旗下的编程⼯具;
2012 年 Qt 又被 Digia 公司收购;
2014 年 4 ⽉ 跨平台的集成开发环境 Qt Creator3.1.0 发布,同年 5 月 20 日发布了 Qt 5.3 正式版,至此 Qt 实现了对 IOS、Android、Embedded 等各平台的全⾯⽀持。
1.3 Qt的优点
  • 跨平台,几乎支持所有的平台;
  • 接口简单,容易上手,学习 QT 框架对学习其他框架有参考意义。
  • ⼀定程度上简化了内存回收机制;
  • 开发效率高,能够快速的构建应用程序。
  • 有很好的社区氛围,市场份额在缓慢上升。
  • 可以进行嵌入式开发。

二、Qt HelloWorld程序

通过可视化操作实现

1. 首先我们双击 "widget.ui"文件

2. 拖拽"标签"至UI设计界面中,并双击修改标签内容;

到这一步我们可以发现此时的界面中已经有了一个helloworld,但是我们回头翻看一下代码,发现代码没有变,那Qt是如何做到的呢?其实我们通过拖拽的方式会生成一个UI文件,实际上是以XML格式存储的,这个文件描述了UI的布局,当我们运行时,编译器就会根据这个XML文件生成对应的C++代码来实现界面

通过代码实现

要在窗口上显示一个标签,我们需要再Widget.cpp文件中创建一个QLabel对象,而QLabel就是一个类,在Qt中,通常这个类所在的头文件名是和类名同名的,所以我们也需要输入#include<QLabel>的头文件

推荐通过new方式在堆上创建对象,随后调用setText函数,就可以实现:

实现的方式还有很多,例如QPushButton、Line Edit 、Text Edit 等等

三、项目文件解析

当我们创建好一个文件后,发现qt会自动生成一些文件,接下来我们简单讲解一下这些文件大概是干嘛的

3.1 .pro文件

工程新建好之后,在工程目录列表中有⼀个后缀为".pro"的文件,".pro"文件就是工程文件(project) ,它是qmake自动生成的用于生产makefile的配置文件。它包含了项目的配置信息,如包含的Qt模块、目标应用程序的名称、模板类型以及源文件列表等。

3.2 Widget.h文件

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

3.3 main文件解析

使用qt creator创建任意新项目后都会形成如下代码:

说明:

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

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

3. QApplication为应用程序类,这个类的对象有且只有唯一

  • QApplication管理图形用户界面应用程序的控制流和主要设置。
  • QApplication是Qt的整个后台管理的命脉。它包含主事件循环,在其中来自窗口系统和其它资源的所有事件处理和调度。它也处理应用程序的初始化和结束,并且提供对话管理。
  • 对于任何⼀个使用Qt的图形用户界面应用程序,都正好存在⼀个QApplication对象,而不论这个应用程序在同⼀时间内是不是有0、1、2或更多个窗口。

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

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

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

3.4 Widget.cpp文件

widget.cpp文件是类Widget的实现代码,所有在窗体上要实现的功能添加在此文件中;

3.5 Widget.ui文件

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

四、查看帮助文档

方法1:鼠标对住要查询的类型或者方法名,直接按F1

方法2:

点击左侧边栏的帮助,显示如下

方法3:找到Qt Creator的安装路径,在bin目录下找到 assistant.exe 双击打开

使用示例:

注意:因为Qt很多类都涉及继承,当我们要找一个对象的方法在这个类的文档中没有找到时,可以在找一找他的父类,或者父类的父类,因为这个方法可能是他继承来的

五、对象树

引入:

在上面用代码创建helloworld的实例中,我们在Widget的构造函数中new出了一个QLabel的对象,但是我们却没有释放它,这难道不会造成内存泄露的问题吗,Qt是中通过对象树来解决这个问题的(要注意我们在创建QLabel对象时给他传了一个父类指针)

解释:

在Qt中创建很多对象的时候会提供⼀个Parent对象指针,下⾯来解释这个parent到底是干什么的?

QObject是以对象树的形式组织起来的。

  • 当创建⼀个 QObject 对象时,会看到 QObject 的构造函数接收⼀个 QObject 指针作为参数,这个参数就是 parent,也就是父对象指针。
  • 这相当于,在创建 QObject 对象时,可以提供⼀个其父对象,我们创建的这个 QObject 对象会自动添加到其父对象的 children() 列表。
  • 当父对象析构的时候,这个列表中的所有对象也会被析构。(注意,这里的父对象并不是继承意义上的父类!)

这种机制在GUI程序设计中相当有用。例如,⼀个按钮有⼀个 QShortcut(快捷键)对象作为其子对象。当删除按钮的时候,这个快捷键理应被删除。这是合理的。

QWidget是能够在屏幕上显示的⼀切组件的父类。

  • QWidget继承自 QObject ,因此也继承了这种对象树关系。⼀个孩子自动地成为父组件的⼀个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭⼀个对话框的时候,应用程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该⼀起被删除。事实就是如此,因为这些都是对话框的子组件。
  • 当然,我们也可以自己删除子对象,它们会自动从其父对象列表中删除。比如,当我们删除了⼀个工具栏时,其所在的主窗口会自动将该工具栏从其子对象列表中删除,并且自动调整屏幕显示

Qt引入对象树的概念,在⼀定程度上解决了内存问题。

  • 当⼀个 QObject 对象在堆上创建的时候,Qt会同时为其创建⼀个对象树。不过,对象树中对象的顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。
  • 任何对象树中的 QObject 对象 delete 的时候,如果这个对象有 parent,则自动将其从 parent的 children()列表中删除;如果有孩子,则自动 delete 每⼀个孩子。Qt 保证没有 QObject 会被delete 两次,这是由析构顺序决定的。

如果 QObject 在栈上创建,Qt保持同样的行为。正常情况下,这也不会发生什么问题。来看下⾯的代码片段:

作为父组件的 window 和作为子组件的 quit 都是 QObject 的子类(事实上,它们都是QWidget的子类,而QWidget 是QObject的子类)。这段代码是正确的,quit的析构函数不会被调用两次,因为标准 C++要求,局部对象的析构顺序应该按照其创建顺序的相反过程。因此,这段代码在超出作用域时,会先调用 quit 的析构函数,将其从父对象 window 的子对象列表中删除,然后才会再调window的析构函数。

但是,如果我们使用下面的代码:


 

情况又有所不同,析构顺序就有了问题。我们看到,在上面的代码中,作为父对象的 window 会首先被析构,因为它是最后⼀个创建的对象。在析构过程中,它会调用子对象列表中每⼀个对象的析构函数,也就是说, quit 此时就被析构了。然后,代码继续执行,在 window 析构之后,quit也会被析构,因为 quit 也是⼀个局部变量,在超出作用域的时候当然也需要析构。但是,这时候已经是第⼆次调用quit的析构函数了,C++不允许调用两次析构函数,因此,程序崩溃了。

所以在Qt中,尽量在构造的时候就指定parent对象,并且大胆在堆上创建。

Qt对象树如图:

代码验证自动释放:

myqlabel.h

我们自己创建一个类,让他继承QLabel类,然后通过在构造函数和析构函数打日志的方式来观察释放情况

myqlabel.c

Widget.cpp

当我们关闭对话框时就会自动调用析构函数,析构结果如下:

注意:调用析构函数和释放内存并非是同⼀件事情.

对象树确保的是先释放子节点的内存,后释放父节点的内存,而析构函数的调用顺序则不⼀定遵守上述要求.因此看到子节点的析构执行顺序反而在父节点析构顺序之后


http://www.kler.cn/a/413695.html

相关文章:

  • OminiControl:一个新的FLUX通用控制模型,单个模型实现图像主题控制和深度控制
  • 学习ASP.NET Core的身份认证(基于Session的身份认证1)
  • 速度革命:esbuild如何改变前端构建游戏 (1)
  • 九、Ubuntu Linux操作系统
  • Linux入门攻坚——39、Nginx入门
  • 排序算法之选择排序篇
  • SpringBoot+MyBatis+lombok进行数据库操作的小案例
  • React Native 性能调试指南
  • 时钟使能、
  • 安装QT6.8(MSVC MinGW)+QT webengine+QT5.15.2
  • git 命令查询
  • 渗透的本质是信息收集——一点思考
  • componentReceivePropsreact class生命周期
  • 【vue3实现微信小程序】从轮播图到公告栏的前端开发之旅
  • 小R的二叉树探险 | 模拟
  • Windows 11 搭建 Docker 桌面版详细教程
  • 读书笔记_《创华为.任正非传》_精华书摘
  • 241125学习日志——[CSDIY] [ByteDance] 后端训练营 [16]
  • 【通俗理解】Adaptive Gradient Algorithm(自适应梯度算法)——从梯度下降到优化器选择
  • 《Gin 框架中的表单处理与数据绑定》
  • 跳表(Skip List)
  • TCP网络套接字
  • Python中3中并发对比
  • 【从零开始的LeetCode-算法】3202. 找出有效子序列的最大长度 II
  • 整合Springboot shiro jpa mysql 实现权限管理系统(附源码地址)
  • Reachy 2,专为AI与机器人实验室打造的卓越开源双臂移动操作平台!