Qt——1、初识Qt

初识Qt

1、环境搭建

1.1、安装Qt SDK

首先从Qt官方网站中下载安装包,下载之后打开安装包进行安装。

安装需要你先进行一个Qt官方账号的注册,这里大家自行注册,然后接受要求下一步即可。

这里可以自行选择安装目录,然后下一步即可。



这里记得点开这两个选项,然后选择MinGW64位的编译器,如果你需要使用vs进行开发,可以选择MSVC。接着一直下一步安装即可。

安装好之后,我们还需要给Qt配置一下环境变量:

给系统环境变量Path添加如图所示的路径。配置这个环境变量主要是为了让操作系统/Qt Creator能够找到Qt SDK中提供的exe文件,同时也是为了运行qt程序的时候能够找到dll动态库。


认识Qt SDK中的重要工具

第一个Assistant是Qt的官方英文文档,后续在学习过程中可以查看。
第二个Designer是Qt提供的可以使用拖拽的方式快速开发图形化界面的工具,不过后续我们使用的Qt Creator中已经集成了。
第三个Linguist是用来实现国际化的程序,允许你单独创建一个语言配置文件,把界面上的需要用到的各种文字都配置到文件中,并且在文件中提前把各种语言的翻译都配置进去,可以起到一键切换语言的效果。
第四个就是一个编译器的命令行程序。
第五个是Qt的集成开发工具,是后续学习Qt过程中主要使用的工具。


1.2、使用Qt Creator创建项目

打开Qt Creator,点击上方菜单栏的文件,选择新建文件或项目。

如果想使用Qt写一个GUI程序,左侧就选择Application。然后右侧选择第一个表示GUI程序,第二个表示TUI程序。后面也可以看到Qt不仅仅支持C++,也支持Python和Java。
传统开发GUI的方式叫做Qt Widget,Qt Quick是Qt搞出的一套新的用来开发GUI的方式。



接着配置项目的创建路径和项目的名称。



接着是构建系统的设置。
通过Qt写的程序,涉及到一系列的元编程技术。Qt框架会在编译的时候,先自动调用一系列的生成工具,基于你写的代码生成一系列的C++代码,最终编译的代码是这些生成的代码。这块我们使用qmake即可。



刚开始上手我们就选择简单的QWidget,QMainWindow、QWidget、QDialog就是我们生成代码要继承的那个父类,Qt中内置的类都是以Q开头的。





接着我们点击右下角的绿色按钮,就会编译运行项目。然后就可以看到一个MyWidget的框框。


1.3、项目代码解释


1、QApplication:编写Qt图形化界面程序,一定要有QApplication对象。
2、MyWidget就是我们前面自己设置的类名,继承自QWidget,这里通过show方法将控件显示出来,还可以通过hide方法将控件隐藏。这两个方法都是由父类QWidget提供的。
3、最后调用QApplication的exec函数,表示让程序执行起来。



1、QT_BEGIN_NAMESPACE / QT_END_NAMESPACE:这是 Qt 定义的宏,用于确保代码在支持命名空间的 Qt 构建环境中正常工作(防止命名冲突)。 然后声明了名为ui的namespace中有一个MyWidget类。
2、MyWidget类继承自QWidget,这里的QWidget就是刚开始创建项目时我们手动选择的父类。另外要使用Qt内置的类需要包含头文件。Qt的设定:Qt中内置的类包含的头文件和类型一致。不过并不是所有类都需要包含头文件,因为可能存在间接包含的情况,所以后续写代码先使用,如果不存在再包含即可。
3、Q_OBJECT是Qt内置的宏。当Q_OBJECT展开之后会生成一大堆代码。Qt中有一个非常核心的机制信号和槽,如果某个类想使用信号和槽,就必须引入Q_OBJECT这个宏。
4、构造函数中我们发现有一个父类的指针,这是因为Qt中引入了对象树机制。当我们创建一个Qt对象,可以把这个Qt对象给挂到对象树上面,而往树上挂需要指定父节点。这里的对象树就是一颗N插树。
5、Ui::Widget* ui,这个主要是和form file密切相关的。



1、ui_mywidget.h是form file被qmake生成的头文件。
2、然后就是构造函数和析构函数的一些操作了。new一个ui对象赋值给ui指针,接着调用setupUi函数,将form file生成的界面和当前Widget关联起来。


接下来看一些关键的form file,我们直接双击打开项目下面的.ui文件:


当双击ui文件时,此时Qt Creator就会调用Qt Designer打开ui文件,图形化的编辑界面。看左侧就是Qt的控件,可以直接拖拽到MyWidget中,右侧还可以编辑控件的属性,可以影响控件的具体行为。

接着我们再点击左侧的编辑按钮:

此时就会显示这个ui文件的文本内容。这个文件的格式是xml格式,和html格式非常相似,都是采用成对标签来表示数据的。但是xml的标签,标签的含义,都是由程序员自己来定的,这里我们看到的标签就是开发Qt大佬定的。
Qt中使用xml文件去描述程序的界面是咋样的,同时qmake会调用相关的工具根据这个xml生成一些C++代码,从而把完整的界面构造出来。

下面再看.pro文件:

qmake搭配.pro启动的作用和Makefile类似。Qt Creator把这个过程中编译的细节都封装好,不需要过多关注。只需要点击运行按钮直接编译运行即可。

我们上面看到的这些文件都是源代码,但是在编译的过程中还会生成一些中间文件,我们打开当前目录所在文件夹,可以看到还有另一个文件夹:

在运行一次程序之后,就会在项目同级目录下生成一个builx-xxx目录,这个目录就是在构建运行项目过程中生成的一些临时文件。其中,编译Qt程序还是会用到makefile,只不过这个makefile是由qmake生成的。然后debug目录下还可以看到一个可执行程序,这个就是我们最终编译形成的可执行程序。
另外还有一个ui_mywidget.h文件,这个就是由mywidget.ui生成的头文件:

可以看到.h头文件中声明的Ui::MyWidget就是Ui_MyWidget,然后cpp文件中构造函数调用了setupUi生成界面具体细节。


2、Qt初识

2.1、HelloWorld程序

首先还是类似上面创建一个新的项目,项目名称为HelloWorld,继承的父类还是QWidget。
现在我们想在界面上显示字符串HelloWorld,这里有两种实现方式:
1、通过图形化的方式,在界面上创建一个控件显示Hello World。
2、通过纯代码的方式,在界面上创建控件显示HelloWorld。
下面我们先采用第一种方式:


双击ui文件,然后在左边的控件列表找到label,直接拖拽到界面中,拉大一些然后双击输入字符串即可。同时我们可以看到右边通过树形结构的方式显示了当前界面上有哪些控件。

此时我们点击编辑,看看xml文件有什么变化:

可以看到xml格式中多出了一段代码,当我们运行程序,qmake就会在编译的时候基于这个文件内容生成C++代码,通过C++代码构建出界面内容,这都是自动完成的。

同时我们再去看看前面说过的构建项目时,通过ui文件生成的头文件,看看里面的代码有什么变化:


下面实现第二种方式,通过编写代码,重新创建一个HelloWorld_2项目:

接着我们需要在Widget构造函数中进行添加。
一般通过代码来构造界面的时候,通常会把构造界面的代码放到Widget/MainWindow的构造函数中。


在使用QLabel的时候,需要引入头文件,引入头文件的时候我们发现有两种头文件。在上古时期,Qt采用的时qlabel.h风格的头文件。C++98之后,规定统一使用<cstdio>的方式,因此有了现在这种方式。


另外,创建QLabel有两种方式,一种是在堆上new一个对象,另一种是直接在栈上创建。我们推荐在堆上创建,同时在构造函数传入this指针,指明父节点。
另外,我们发现这里函数参数是QString。这是因为Qt诞生于1991年,当时C++标准库还没有形成,当时表示一个字符串可以用C风格字符串,也可以用C++的string,但是都不太好用。而Qt为了让自己开发更加顺畅,搞了一套基础类支持开发,包括但不限于:字符串QString、动态数组QVector、链表QList、字典QMap...
之后C++容器也打磨得很好了,但是Qt自己包装得容器类也不可能删了,因此和标准库共存了。因此进行开发得时候,可以使用Qt提供的容器,也可以使用C++标准库的容器。但是Qt原生api中,涉及到的接口都是用的Qt自己的容器。

后续还会经常看到QString的东西,很少看到std::string,QString和std::string也可以很方便的相互转换。而且QString里面对于字符编码做了处理,std::string则没有。

可以看到,默认创建出来的控件是位于左上角的,而拖拽的方式可以在任意位置。


2.2、对象树

前面的代码中我们直接new了一个QLabel对象,并没有delete,这会不会导致内存泄漏呢?
实际上并不会内存泄漏,这个label对象会在合适的时候被析构释放,而之所以会被释放是因为把这个对象挂到了对象树上。

前端开发也涉及到类似的对象树DOM,本质上是一个N叉树,通过树结构把界面上各种元素组织起来。Qt中也是类似的。如下:

通过对象树把这些内容组织起来,最主要的目的是,能够在合适的时机(窗口关闭/销毁)把这些对象统一释放掉。
如果某个对象提前销毁了,此时对应的控件在界面上就不存在了。

比如我们把创建QLabel变成栈上的方式:

这时候我们就发现看不到字符串了,这是因为栈上创建的在构造函数结束后就会销毁,所以就看不到了。


下面我们演示一下我们new出来的对象最后确实会被释放掉,由于QLabel是Qt官方提供的类型,在析构函数中并没有打印信息可以让我们看,所以我们需要自定义一个类来进行验证。首先创建一个新项目名为:ObjectTree,还是继承QWidget。接着我们再创建一个类:

首先Qt Creator虽然帮我们生成了对应类,但是我们还需要自己添加QLabel的头文件。 另外我们需要在构造函数中添加一个指针,并添加一个析构函数用来输出观察。
在Qt Creator可以直接使用F4来快速进行对应的.h和.cpp文件切换。可以在对应的函数声明按下Alt + enter,可以自动在cpp文件中添加定义。

在构造函数中调用了父类QLabel的构造函数,并传入parent指针,将我们自定义类型挂到对象树中。并且在析构函数中实现打印语句,将来窗口关闭销毁的时候,就可以看到自动销毁我们所定义的MyLabel类。


接着再Widget构造函数中添加对应的代码,创建一个MyLebel对象。然后运行程序,可以看到正常显示文字。



当我们把窗口关闭之后,就会把对象树上的所有对象销毁,此时查看应用程序输出,就发现打印了对应的信息。不过这里由于编码格式的原因,导致了乱码问题。
首先对于一个汉字来说,他可能占2个字节或者占3个字节,取决于编码方式是gbk还是utf8,这里乱码就是由于编码方式不一致导致的。

那么我们输出的字符串是在cpp文件里面的,所以字符串的编码方式就和cpp文件的编码方式一致。我们通过记事本打开该文件:

记事本的右下角就会显示编码方式,可以看到这是utf8编码的。而Qt Creator的终端没法正常显示,说明他肯定不是utf8编码,那怎么解决呢?首先在Qt Creator中并没有找到终端编码的修改方式,另外我们也不打算直接修改cpp文件的编码方式,因为目前utf8编码还是主流。
这里的解决办法是:采用QString,可以自动帮助我们进行编码处理。不只是QString,Qt中也有专门用来打印日志的工具,也能自动处理编码方式。

Qt中提供了一个qDebug()工具,借助这个工具就可以完成打印日志的过程,很好的处理字符编码问题。

QDebug是Qt的内置类,但是我们并不会直接使用这个类,而是通过qDebug()这个宏,该宏封装了QDebug对象,可以当做cout来使用。
后续在Qt中,如果想通过打印日志的方式输出一些调试信息,优先使用qDebug。使用cout也行,但是在windows上容易出现乱码,如果在Linux上使用Qt Creator一般就没事,因为Linux编码一般都是utf8。

另外,使用qDebug还有一个好处,打印的调试信息是可以统一关闭的。可以在发布版本的时候通过编译开关,实现一键关闭qDebug。

小结:
1. 认识了QLabel类,能够在界面上显示字符串。通过setText可以设置参数QString。
2. 对象树,Qt中通过对象树统一管理界面的控件对象。推荐使用new的方式在堆上创建对象,挂到对象树上,在合适的时机通过对象树统一释放对象。创建对象的时候在构造函数中指定父对象。如果你没有挂到对象树上,记得手动释放。
3. 继承Qt内置的类,可以达到对现有控件进行功能扩展。Qt内置的QLabel类,没办法看到销毁的过程,我们创建MyLabel类继承QLabel,并重写析构函数,可以直观的看到对象的释放过程。
4. 在Qt中使用qDebug实现日志打印。


2.3、编辑框实现HelloWorld

完成HelloWorld可以通过很多种控件来实现。接下来采用编辑框实现:首先创建一个新项目,还是继承QWidget类。
编辑框分为单行编辑框:QLineEdit,多行编辑框:QTextEdit。这里我们使用单行编辑框。


双击ui文件,然后在左侧找到LineEdit,直接拖拽到Widget中,然后双击输入HellWorld,也可以在右侧的属性中找到text属性进行修改。

或者通过以下代码的方式实现:

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QLineEdit* edit = new QLineEdit(this);
    edit->setText("Hello World");
}

2.4、按钮实现HelloWorld


按钮也分为许多类,我们使用PushButton。当我们运行后发现按钮并没有什么反应,实际上按钮应该是要和某些事件关联的,当点击按钮后触发事件。
接下来我们就要实现这个功能,这就涉及到了Qt中信号和槽机制。本质就是给按钮的点击操作关联上一个处理函数,当用户点击后,执行这个处理函数。

这里就涉及到了一个connect函数,Qt中的connect是QObject这个类提供的静态函数,这个函数的作用是连接信号和槽。

当实现了上述代码,再次运行程序点击按钮就可以看到text的变化了。另外我们可以到前面说的编译后会生成一个build-xxx目录里面,看一下ui_widget.h文件的内容:

当我们把objectName的值改了,那么ui里面的变量名也会跟着变化。因此可以根据objectName的值来获取到对应的控件变量。
可以看到这个按钮对象是在Ui_Widget对象中的,然后Ui::Widget又继承了Ui_Widget对象,因此就可以通过左侧的ui指针->访问到里面的成员变量。

下面我们通过代码实现,并对比代码和图形化界面实现的区别:

对于纯代码实现,由于按钮是我们自己new出来的,所以需要把该按钮对象设置为Widget的成员变量,以便在后续的处理函数能够访问到。而使用图形化的方式,此时由Qt自动生成,直接通过ui即可访问。


2.5、Qt中的命名规范

1、起的名字要有描述性,不要使用abc、xyz这种无规律的名字来描述。
2、如果名字比较长,由多个单词构成,就需要使用适当的方式来区分不同的单词。之前我们比较常见的就是蛇形命名法,比如:unordered_map、priority_queue。而在Qt中,偏好使用大写字母进行单词分割,形如:studentCount、QApplication、QWidget,也就是驼峰命名法。大驼峰给类,小驼峰给变量/函数。


2.6、使用帮助文档

打开帮助文档有三种方式:
1、光标放到要查询的类名/方法名上,直接按F1。

2、直接点击左侧的帮助按钮。

3、直接在开始中搜索assistant并打开。


2.7、Qt窗口坐标体系

下面我们创建一个项目,还是继承QWidet,并创建一个QPushButton。

我们发现这个按钮默认就在坐标(0,0)的位置,也就是左上角。另外我们还发现上面还有一部分标题和按钮,这个是系统自动生成,不在Widget范围中。也就是下面的这一部分才是代码中创建的Widget范围。
下面我们可以使用move函数设置按钮的位置:


这里的单位是像素。

相关推荐
Arms2062 小时前
python时区库学习
开发语言·python·学习
兵哥工控2 小时前
MFC 对话框Alt+F4退出程序实例
c++·mfc
无名的小三轮2 小时前
第二章 信息安全概述
开发语言·php
王老师青少年编程2 小时前
2024年9月GESP真题及题解(C++七级): 小杨寻宝
c++·题解·真题·gesp·csp·七级·小杨寻宝
清水白石0082 小时前
深入 Python 对象模型:PyObject 与 PyVarObject 全解析
开发语言·python
独自破碎E2 小时前
说说Java中的反射机制
java·开发语言
一直都在5722 小时前
SpringBoot3 框架快速搭建与项目工程详解
java·开发语言
子云之风2 小时前
LSPosed 项目编译问题解决方案
java·开发语言·python·学习·android studio
凯子坚持 c2 小时前
C++大模型SDK开发实录(一):spdlog日志封装、通用数据结构定义与策略模式应用
数据结构·c++·sdk·策略模式