Qt 基础编程核心知识点全解析:含 Hello World 实现、对象树、坐标系及开发工具使用

基础代码解读

Qt Hello World 程序

方法一:纯代码⽅式实现

方法二:通过图形化的方式实现

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

(2)拖拽控件⾄ui界⾯窗并修改内容;

(3)构建并运⾏,效果如下所⽰:

项⽬⽂件解析

.pro ⽂件解析

⼯程新建好之后,在⼯程⽬录列表中有⼀个后缀为 ".pro" 的⽂件, ".pro" ⽂件就是⼯程⽂件 (project) ,它是 qmake ⾃动⽣成的⽤于⽣产 makefile 的配置⽂件。如图所⽰:

Qt 编程注意事项

Qt Creator 中的快捷键

  • 注释:ctrl+/
  • 运⾏:ctrl+R
  • 编译:ctrl+B
  • 字体缩放:ctrl+⿏标滑轮
  • 查找:ctrl+F
  • 整⾏移动:ctrl+shift+/
  • 帮助⽂档:F1
  • ⾃动对⻬:ctrl+i;
  • 同名之间的.h和.cpp的切换:F4
  • ⽣成函数声明的对应定义:alt+enter

使⽤帮助⽂档

打开帮助⽂档有三种⽅式.实际编程中使⽤哪种都可以.

1、光标放到要查询的类名/⽅法名上,直接按F1

2、Qt Creator 左侧边栏中直接⽤⿏标单击"帮助"按钮:

点击"帮助"之后,出现如下图⽰界⾯:

3、找到 Qt Creator 的安装路径,在 "bin" ⽂件夹下找到 assistant.exe,双击打开;

使⽤⽰例

1、新建项⽬,在新建的项⽬中使⽤ Qt 中的 "QpushButton" 控件。

2、打开帮助⼿册,在 "索引" ⾥⾯输⼊ "QpushButton";

认识对象模型(对象树)

在 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 的对象树机制虽然在⼀定程度上解决了内存问题,但是也引⼊了⼀些值得注意的事情。

注意:在 Qt 中,尽量在构造的时候就指定 parent 对象,并且⼤胆在堆上创建。

Qt对象树如图:

上述代码中,在Qt中不会存在内存泄漏,虽然我们没有手动进行释放,但是我们将Label对象挂到了Qt对象树上

创建一个类,自定义一个析构函数,在析构函数中完成打印

1.选中⼯程名,⿏标右键------->"add new..."(或"添加新⽂件")

2.选择 "choose...",弹出如下界⾯;

3.点击 "下⼀步",弹出如下对话框;

4.点击 "完成" 之后,⼿动创建类的头⽂件以及源⽂件会⾃动添加到⽬标⼯程中;

5.修改头⽂件;

6.编写源⽂件;

7.编译并运⾏;

8.当关闭弹出的对话框时,就会⾃动调⽤按钮的析构函数;

9.观察析构函数的执⾏顺序;

10.执⾏结果:

12、执⾏结果分析:

对象树确保的是先释放⼦节点的内存,后释放⽗节点的内存.⽽析构函数的调⽤顺序则不⼀定遵守上述要求.因此看到⼦节点的析构执⾏顺序反⽽在⽗节点析构顺序之后,调⽤析构函数和释放内存并⾮是同⼀件事情.

注意:

Qt 窗⼝坐标体系

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

对于嵌套窗,其坐标是相对于⽗窗⼝来说的。 ⽰例:使⽤Qt中的坐标系设置控件的位置;

运⾏结果如下图⽰:

相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00614 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术14 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript