Qt学习笔记
- [1 使用Qt Creator 新建项目](#1 使用Qt Creator 新建项目)
- [2 项目代码解释](#2 项目代码解释)
- [3 创建第一个 Hello World 程序](#3 创建第一个 Hello World 程序)
- [4 关于内存泄漏问题](#4 关于内存泄漏问题)
- [5 Qt 中的对象树](#5 Qt 中的对象树)
- [6 关于 qDebug()的使用](#6 关于 qDebug()的使用)
- [7 使用其他方式创建一个 Hello World 程序(编辑框和按钮方式)](#7 使用其他方式创建一个 Hello World 程序(编辑框和按钮方式))
- [8 关于 Qt 中的命名规范 / 快捷键 / 查询文档](#8 关于 Qt 中的命名规范 / 快捷键 / 查询文档)
- [9 Qt 窗口坐标系](#9 Qt 窗口坐标系)
本文使用的是Qt6.2
1 使用Qt Creator 新建项目
新建项目
打开Qt Creator 界面后点击左上角的 文件 选择 new project
选择项目模板
项目模板 | 说明 |
---|---|
Application | Qt应用程序,包括普通窗体程序和QtQuick程序 |
Libary | 可以创建动态库、静态库以及Qt Quick 扩展插件、QtCreator 自身插件 |
其他项目 | 可以创建单元测试项目、Qt4设计师自定义控件、子目录项目等 |
Non-Qt-Project | 非Qt项目。可以创建纯C或C++项目 |
import Project | 导入项目。从版本控制系统管理的软件项目导入旧的项目 |
常用的是第一类,选中后,在右侧会显示出Qt应用程序的五个子模版:
- Qt Widgets Application :普通窗体模板,传统基于部件的窗体界面程序
- Qt console Application :Qt 控制台应用程序。因为Qt主要用于图形界面设计,这个控制台项目基本不用。
- Qt for Python:在Python 下用LGPL的许可来开发闭源Qt软件。
- Qt Quick Application: Qt 提供的一种高级用户界面技术,使用它可以方便快速的为移动以及嵌入式设备开发流畅美观的用户界面。QtQuick模块是开发QML应用的标准库,提供了使用QML创建用户界面所需的一切,包括可视化、交互、动画、模型、视图、粒子效果以及着色效果等。
选择了不同的项目模板,Qt Creator 就会在项目创建完毕以后生成不同的基础代码
选择项目路径
注意创建路径名称不能有中文!!!
选择构建系统
使用默认的qmake即可
Qt中的构建工具有三种可供选择,分别是: qmake、CMake、 Qbs,下面依次介绍。
- qmake: qmake是一个构建工具(build tool) ,用于自动生成makefile文件。qmake支持跨平台构建。qmake编辑的是一个后缀名为.pro的文件。
- CMake: CMake是一个跨平台的构建工具。CMake本身不是一个编译器,其实就是生成一个让编译器能读懂编译流程的文件工具。让CMake自动生成构建系统,例如Makefile和Visual Studio项目文件。CMake 是一个第三方工具,有自己的文档。
- Qbs: Qbs (Qt Build Suite: Qt构建套件)同qmake、 CMake一样都是构建工具。Qbs号称是新一代的构建工具,比qmake编译速度更快。Qbs 没有绑定Qt版本,它从项目文件的高级项目描述中生成一个正确的依赖表。而传统的MakeFile生成工具如qmake和CMake,其在生成MakeFile文件后将实际的命令交给Make工具去执行。
Qt官方声明,因市场原因,弃用Qbs。对于Qt用户来说,qmake是当前使用最广泛的构建工具,CMake其次。
填写类信息设置界面
对于基类的选择,目前有三种基类
基类 | 说明 |
---|---|
QMainWindow | 主窗口类,一般用于较为复杂的应用程序,除了中央客户区界面,还包括菜单栏、工具栏、状态栏以及多个可停靠的工具对话框等 |
QWidget | 最简单、最基本的窗体程序,里面可以放置多个控件实现程序功能. |
QDialog | 基于对话框的程序,对话框一般用于弹窗, 也可以用于主界面显示。对话框是从QWidget继承而来的,并丰富了一些能,如模态显示和返回值等 |
三者关系如下图
选择语言和翻译文件
这里的语言不是编程语言,而是例如"中文" "英文" 这种语言
由于暂时不需要考虑国际化问题,直接点击下一步即可
选择 Qt 套件
Qt套件是指Qt程序从编译链接到运行环境的全部工具和Qt类库的集合,对于MinGW版本Qt程序生成和调试,至少需要MinGW中的编译器g++ (自 动调用链接器)、g++ 配套的基础库、调试器gdb还有使用MinGW环境编译而成的Qt类库自身。默认情况下,在上面Kit Selection里选中全部套件。
选择版本控制系统
如果想把代码提交到github可以在这里选择
项目构建完成
点击左下角运行按钮,或者按CTRL+R,查看效果
2 项目代码解释
main.cpp 文件解析
QApplication 为应用程序类;代码中 QApplication a ,a 为应用程序对象,有且仅有一个;
- QApplication 管理图形用户界面应用程序的控制流和主要设置;
- QApplication是Qt的整个后台管理的命脉。它包含主事件循环,在其中来自窗口系统和其它资源的所有事件处理和调度。它也处理应用程序的初始化和结束,并且提供对话管理。
- 对于任何一个使用Qt的图形用户界面应用程序,都正好存在一个QApplication对象,而不论
这个应用程序在同一时间内是不是有0、1、 2或更多个窗口。
Widget 为刚才创建项目的时候,所选的类名
- w.show() 调用show函数显示窗口
- Widget 的父类是QWidget,函数由该父类提供
a.exec() :程序进入消息循环,等待对用户输入进行响应。这里main()把控制权转交给Qt, Qt 完
成事件处理工作,当应用程序退出的时候exec()的值就会返回。在exec() 中,Qt接受并处理用户
和系统的事件并且把它们传递给适当的窗口部件。
widget.h 文件解析
- 在 Qt 中,头文件的命名是有规律的,一般类名和头文件的命名相同。
- Q_OBJECT 本质上是一个宏,展开后是一长段代码。如果某个类想使用信号和槽机制,就需要引入这个宏。
- 图中第17行代码为构造函数,这里在后面的"对象树"中会再次提到。
- Ui::Widget *ui 和form file文件密切相关,通过该指针,可以访问UI界面中的任意控件。
widget.cpp 文件解析
widget.ui 文件解析
点击form file 中的 ui 文件,打开图形编辑界面
点击左侧的"编辑",查看该ui界面的本体
该格式为XML格式,和HTML格式类似
Qt 中使用XML文件去描述程序的界面,进一步会结合qmake 调用相关的工具,依据XML文件生成C++代码,从而把完整的界面构造出来
.pro 文件解析
- .pro 是Qt项目的工程文件,也是qmake工具构建时的重要依据。
- .pro 类似与Makefile 文件,qmake搭配.pro文件起到的作用和Makefile是类似的
- 图中第一行代码是要引入的QT模块,后面学习一些内容的时候会修改这里
中间文件
如果编译运行Qt项目,构建过程中还会生成一些中间文件,如下图,打开资源管理器查看
打开后,返回上一级会看到多出来一个build-xxx文件夹,这个文件夹里面就是项目在运行过程中生成的一些临时文件
- 可以看到编译Qt程序,还是会用到makefile文件,只不过不需要我们手动去写,而是qmake自动生成的。
- widget.ui 由xml 生成的ui_widget.h 文件也在图中,双击打开查看
之前提到的 widget.h 里的ui指针就是该类的指针
- 点击debug 文件,可以看到最终生成的可执行程序
直接运行,效果和在Qt Creator 中运行是相同的效果。(运行失败的话,看看有没有配置环境变量)
3 创建第一个 Hello World 程序
利用 Qt 创建一个Hello World 程序有两种方式。分别是图形化的方式和纯代码的方式。
图形化方式
图形化方式比较简单,打开 ui 界面,然后找到 Label标签 拖动到编辑界面,然后输入文字即可。
运行程序,查看效果。
在 Qt Designer 的右边可以查看有哪些控件,label 实际上就是一个界面上用来显示字符串的控件
在编辑界面可以看到XML文件中多了一段代码,qmake就会在编译项目的时候,基于这个内容生成一段C++代码,构建出界面内容。
纯代码方式创建Hello World 程序
一般通过代码来构造界面的时候,通常会把构造界面的代码放到 Widget 的构造函数中
代码如下,记得包含头文件
运行查看效果
Hello World 程序创建完成。但是文字默认在左上角,通过纯代码的方式也可以修改,后面会讲。
4 关于内存泄漏问题
在这段代码中,在 new 了一个对象之后,却没有 delete ,会不会造成内存泄漏?
答案是在 Qt 中不会造成内存泄漏。此处通过 new 的方式创建对象,就是为了把该对象的生命周期交给 Qt 的对象树统一管理。代码中的 label 对象会在合适的时机被析构释放,这个合适的时机是指在窗口关闭的时候。
5 Qt 中的对象树
Qt 中的对象树,是一颗 N叉树 ,通过该树把界面上的各种元素组织起来。
比如有如下几种元素。
经过对象树组织后,就变成下图所示
使用对象树组织起来,最主要的目的,就是为了在合适的时机,也就是窗口关闭的时候,把这些对象统一释放。
cpp
QLabel *label = new QLabel(this);
代码中传入this 参数是为了将该对象挂在对象树上。通过 new 的方式在堆上建立对象,交给对象树管理。
而之前说的下面这种方式,是不推荐的
cpp
QLabel label(this);
这种在栈上创建的方式,可能存在"提前释放"的问题。运行查看效果。
窗口中没有设定好的 label 控件,因为被提前释放掉了。
6 关于 qDebug()的使用
qDebug() 的使用效果和 std::cout << std::endl 的效果一样,但是比后者好。
原因是 qDebug() 会自动处理编码方式,在 Qt 中如果用 cout 打印文字日志,可能会出现乱码,因为编码不同。
比如在析构函数中加入打印语句。
运行后,然后关闭窗口,自动调用析构函数,查看应用程序输出,会看到乱码
所以通常采用 qDebug() 的方式去打印日志。
qDebug() 还有一个优点就是可以统一打开和关闭,就能方便程序员调试。
在 .pro 文件加入这条代码即可
cpp
DEFINES += QT_NO_DEBUG_OUTPUT
需要 清除 然后重新构建才有效
7 使用其他方式创建一个 Hello World 程序(编辑框和按钮方式)
除了上面使用 label 标签的形式,还可以采用编辑框和按钮的方式。同样分为图形化界面方式和纯代码方式完成。
编辑框图形化方式
如下图所示,编辑框分为单行编辑框和多行编辑框,这里选择单行编辑框即可。拖动到编辑界面,然后输入文字。
运行查看效果。编辑框的内容运行后可以自己修改。
编辑框纯代码方式
纯代码方式和之前介绍过的大同小异。首先需要创建一个 QLineEdit 对象,然后设置文字。
运行查看效果。
按钮图形化方式
在 ui 界面找到 Push Button 然后拖动到图形化编辑界面输入文字
运行查看效果
这个按钮是可以点击的,但是点击了没有反应。如果想要点击了有反应,需要用到信号和槽机制,后面会讲。这里先简单说一下,本质就是给按钮的点击操作,关联一个处理函数,当用户点击的时候,就会执行这个处理函数。
这里需要用到 connect 函数
代码如图所示:
- 第一个参数需要访问到 ui 文件中创建的控件,表示哪个控件发出的信号,在 Qt Designer 中创建一个控件的时候,此时就会给这个控件分配一个 objectName 属性,这个属性的值,要求在界面中是唯一的。qmake 在预处理.ui文件的时候,就会根据这里的 objectname 生成对应的C++代码。这个值可以在ui界面手动修改
- 第二个参数表示发出了个什么信号,这里 clicked 表示点击,当用户点击按钮时就会发出该信号
- 第三个参数表示谁来处理该信号,将第二个参数的信号能够关联到对应的槽函数上,在此之前需要确认关联到哪个对象的槽函数,填写 this ,关联到 widget 对象的槽函数。
- 第四个参数传一个具体的处理函数,这个函数需要我们自己去写处理方式。我们的处理方式是:点击一次按钮,文本在 Hello World!和Hello Qt! 之间来回切换。代码如下:
cpp
void Widget::handClick()
{
if(ui->pushButton->text() == QString("Hello World!"))
{
ui->pushButton->setText("Hello Qt!");
}
else
{
ui->pushButton->setText("Hello World!");
}
}
记得先在头文件声明该函数。声明以后,快速生成函数定义快捷键:alt + 回车
会自动在 .cpp 文件帮我们处理好一些代码
运行查看效果
点击一次按钮
文本内容改变了,再点击一次
点击一次按钮就会在两个文本内容之间来回切换,成功实现我们想要的功能。
纯代码方式实现按钮版 Hello World 程序
纯代码方式实现,首先需要我们自己 new 一个 button 对象,为了能让其他成员函数能够访问该变量,需要将该对象定义为成员变量。
具体代码如下,功能如上面所述
运行查看效果
点击后
再次点击
成功实现。
实际开发以纯代码为主还是图形化界面为主?
这两者都很重要,难分主次。如果当前程序界面,界面内容是比较固定的,此时就会以图形化界面的方式来构造界面。如果当前界面,经常要动态变化,此时就会以代码的方式来构造界面。这两种方式,哪种方便就用哪种,而且这两种方式可以配合使用。
8 关于 Qt 中的命名规范 / 快捷键 / 查询文档
命名规范
- 类名:首字母大写,单词和单词之间首字母大写,也就是大驼峰命名法。如:QPushButton
- 函数名:首字母小写,单词和单词之间首字母大写,也就是小驼峰命名法。如:setText
快捷键
- 注释: ctrl+ /
- 运行: ctrl+ R
- 编译: cttrl+ B
- 字体缩放: ctrl +鼠标滑轮
- 查找: ctrl + F
- 整行移动: ctrl+shift+ ↑/↓
- 帮助文档: F1
- 自动对齐: ctrl+ i;
- 同名之间的.h和.cpp的切换: F4
- 生成函数声明的对应定义: alt + enter
使用帮助文档
打开文档一共有三种方法
- 光标放到要查询的类名/方法名上,直接按F1
- Qt Creator左侧边栏中直接用鼠标单击"帮助"按钮
- 找到Qt Creator的安装路径,在"bin"文件夹下找到assistant.exe,双击打开;
9 Qt 窗口坐标系
坐标体系:以左上角为原点(0,0),X向右增加,Y向下增加
对于嵌套窗口,其坐标是相对于父窗口来说的。
比如图中 QPushButton 的父窗口就是 QWidget,原点就是QWidget 左上角。QWidget没有父元素,相当于父元素就是整个显示器,原点就是显示器左上角。
上面我们提到过,以纯代码的方式创建一个这样一个程序,按钮会默认在左上角,也就是原点(0,0)处,这里的位置是可以改变的。
需要用到 move 函数
把这个按钮相对于原点水平移动200像素,垂直移动300像素,效果如下
还可以设置窗口弹出时的位置。设置为弹出为显示器的原点处
查看效果,在窗口弹出后位置在显示器左上角。
以上是关于 Qt 的一些基础操作,下篇文章是关于 Qt 的信号和槽机制。