目录
一、Qt Hello World 程序
1.使用 “按钮” 实现(创建出来的 按钮 可以点击)
1.1 纯代码方式实现
为了能够让按钮点击之后有效果,就需要涉及到 Qt 中的信号槽机制。它的本质就是给按钮的点击操作,关联上一个处理函数,当用户点击的时候,就会执行这个处理函数。
Qt中的 connect 是 QObject 这个类提供的静态函数,这个函数的作用就是 “连接信号 和 槽”。
实现效果如下:
Qt 中使用 “按钮” 实现交互
1.2 可视化操作实现
(1)双击:" widget.ui " 文件;
(2)拖拽控件至 ui 界面窗口并修改内容;
(3)构建并运行,效果如下所示:
Qt 中使用 “按钮” 实现交互
实际开发中,是通过代码的方式构造界面为主,还是通过图形化的方式构造界面为主呢?
其实这两种都很重要,难分主次!
如果你当前程序界面内容是比较固定的,此时就会以图形化的方式来构造界面。
但是如果你的程序界面经常要动态变化,此时就会以代码的方式来构造界面。
2.使用 “标签” 实现
2.1 纯代码方式实现
实现效果如下图所示:
2.2 可视化操作实现
(1)双击:" widget.ui " 文件:
(2)拖拽 "标签" 至 UI 设计界面中,并双击修改标签内容:
(3)实现效果如下图所示:
3.使用 “编辑框” 实现(可以编辑)
3.1 纯代码方式实现
实现效果如下图所示:
3.2 可视化操作实现
(1)双击:" widget.ui " 文件:
(2)拖拽 "编辑框" 至 UI 设计界面中,并双击修改标签内容:
(3)实现效果如下图所示:
二、Qt 编程注意事项
1.Qt 中的命名规范
- 类名:首字母大写,单词和单词之间首字母大写;
- 函数名及变量名:首字母小写,单词和单词之间首字母大写;
🌻Qt 偏好驼峰命名法,这⼀点不像 C/C++ 等语言偏好蛇形命名。
2.Qt Creator 中的快捷键
- 注释:ctrl + /
- 运行:ctrl + R
- 编译:ctrl + B
- 字体缩放:ctrl + 鼠标滑轮
- 查找:ctrl + F
- 整行移动:ctrl + shift + ⬆/⬇
- 帮助文档:F1
- 自动对齐:ctrl + i
- 同名之间的 .h 和 .cpp 的切换:F4
- 生成函数声明的对应定义: alt + enter
3.使用帮助文档
打开帮助文档有三种方式,实际编程中使用哪种都可以。
1、光标放到要查询的类名/方法名上, 直接按 F1。
2、Qt Creator 左侧边栏中直接用鼠标单击 "帮助" 按钮。
点击 "帮助" 之后,出现如下图示界面:
3、找到 Qt Creator 的安装路径,在 "bin" 文件夹下找到 assistant.exe,双击打开;
使用示例:
- 新建项目,在新建的项目中使用 Qt 中的 "QpushButton" 控件。
- 打开帮助手册,在 "索引" 里面输入 "QpushButton";
4.认识对象模型(对象树)
在 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 保持同样的行为。正常情况下,这也不会发生什么问题。来看下面的代码片段:
{
QWidget window;
QPushButton quit("Quit", &window);
}
作为父组件的 window 和作为子组件的 quit 都是 QObject 的子类(事实上,它们都是QWidget的子类,而QWidget 是 QObject 的子类)。这段代码是正确的,quit 的析构函数不会被调用两次,因为标准 C++ 要求,局部对象的析构顺序应该按照其创建顺序的相反过程。因此,这段代码在超出作用域时,会先调用 quit 的析构函数,将其从父对象 window 的子对象列表中删除,然后才会再调用 window 的析构函数。
但是,如果我们使用下面的代码:
{
QPushButton quit("Quit");
QWidget QWindow;
quit.setParent(&window);
}
情况又有所不同,析构顺序就有了问题。我们看到,在上面的代码中,作为父对象的 window 会首先被析构,因为它是最后⼀个创建的对象。在析构过程中,它会调用子对象列表中每⼀个对象的析构函数,也就是说, quit 此时就被析构了。然后,代码继续执行,在 window 析构之后,quit 也会被析构,因为 quit 也是⼀个局部变量,在超出作用域的时候当然也需要析构。但是,这时候已经是第二次调用 quit 的析构函数了,C++ 不允许调用两次析构函数,因此,程序崩溃了。
由此我们看到,Qt 的对象树机制虽然在⼀定程度上解决了内存问题,但是也引入了一些值得注意的事情。
🍂在 Qt 中,尽量在构造的时候就指定 parent 对象,并且大胆在堆上创建。
Qt对象树如图:
代码示例
1、创建一个新工程并编译运行,生成如下窗口;
2、选中工程名,鼠标右键 -------> "add new..."(或 "添加新文件" )
3、选择 "choose...",弹出如下界面;
4、点击 "下一步",弹出如下对话框;
5、点击 "完成" 之后,手动创建类的头文件以及源文件会自动添加到目标工程中;
6、修改头文件;
7、编写源文件;
8、编译并运行;
9、当关闭弹出的对话框时,就会自动调用按钮的析构函数;
10、观察析构函数的执行顺序;
11、执行结果:
12、执行结果分析:
对象树确保的是先释放子节点的内存, 后释放父节点的内存。
而析构函数的调用顺序则不⼀定遵守上述要求. 因此看到子节点的析构执行顺序反而在父节点析构顺序之后。
注意: 调用析构函数和释放内存并非是同⼀件事情。
5.Qt 窗口坐标体系
坐标体系:以左上角为原点(0,0),X向右增加,Y向下增加。
对于嵌套窗口,其坐标是相对于父窗口来说的。
示例:使用Qt中的坐标系设置控件的位置;
运行结果如下图示: