Qt ,2024年最新靠着这份900多页的PDF面试整理

73 阅读9分钟

main.cpp 包含了三个头文件 QApplicationQWidget 和 前面用 uic 生成的 ui\_hello.h,由于 ui\_hello.h 不包含 Q\_OBJECT 宏,是不需要用元对象编译器 moc 处理的。


main 函数里第一行是图形界面程序入口对象,第二行创建了一个 QWidget 类对象 ww 其实是一个指向对象的指针)作为程序的主窗口,w 自己并没有创建控件或设置窗口属性。


第三行语句:


Ui::Form createUi;


创建了 Ui::Form 类的对象 createUi ,这个对象自己不是一个窗口,它可以为别的窗口对象设置图形界面。


第四行语句:


createUi.setupUi(w);


调用了 createUi 对象的 setupUi 函数,该函数接收一个窗体对象指针,这里是 wsetupUi 函数里面的代码会为 w 创建内部的控件,设置窗体大小等等。


剩下的两行代码是显示主界面,并进入事件处理循环,直到退出。


代码解释完了,接下来我们就开始编译把。


打开 Qt 命令行工具,进入 D:\QtDemo 文件夹:


cd /d D:\QtDemo


执行 g++ 命令:


g++ main.cpp -std=c++0x -I"D:\Qt\5.9\mingw53\_32\include" -L"D:\Qt\5.9\mingw53\_32\lib" -lQt5Core -lQt5Gui -lQt5Widgets -o main


编译链接成功后,在输入`main.exe`命令就可以看到运行效果。以下是完整流程的截图:


![直接使用.ui文件](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/eada549f72db41b4a1d1d5b6d2a10850~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5py65Zmo5a2m5Lmg5LmL5b-DQUk=:q75.awebp?rk3s=f64ab15b&x-expires=1771252551&x-signature=%2BtB0Jk3%2F5mGTVrz6weLDZVEFcLU%3D)


在本例中,图形界面的构建和设置代码全部交给 createUi 对象了。这就是可视化编程的典型示范,创建和设置图形界面的代码就用 Qt Designer 和 uic 来完成,其他的后台代码自己编写。将开发者从凭空想象图形界面变成直接拖动控件,这样不仅直观,而且开发者需要动手编的代码也变少了。


将图形界面设计和后台功能代码相分离,是现代 GUI 程序设计的通用思路。


### 多重继承法使用 .ui 文件


上面的代码非常简单,除了 uic 生成的 ui\_hello.h 和手动编写的 main.cpp,就没其他的代码文件了。主界面是 QWidget 类的对象,然后该对象比较简单,没有自己的代码。


如果要丰富一下主界面的窗口类,那就需要使用从 QWidget 类继承的方式并加上 Ui::Form 类的代码。C++ 如果要同时使用两个类的代码,有两种方式:


* 一种是多重继承的方式,同时用 QWidget 和 Ui::Form 类作为基类;
* 还有一种是使用成员变量,将 Ui::Form 类的对象作为 QWidget 派生类的成员变量,这种也叫单一继承方式,它的基类只有 QWidget。


本小节介绍多重继承方式,而以后的代码都用 QtCreator 自动生成的单一继承方式(Ui::Form 的对象作为成员变量)。


将前面做好的 hello.ui 和 ui\_hello.h 复制到 D:\QtDemo 文件夹,然后再新建三个代码文件,分别是 hellouiwidget.h、hellouiwidget.cpp 和 main.cpp ,每个文件的内容如下。


1. hellouiwidget.h 代码内容



#include <QtWidgets/QWidget> #include <QtWidgets/QLabel> #include "ui_hello.h" class HelloUIWidget : public QWidget, public Ui::Form { Q_OBJECT public: explicit HelloUIWidget(QWidget *parent = 0); ~HelloUIWidget(); protected: void AdjustLabel(); };


hellouiwidget.h 包含了三个头文件 QWidget、QLabel 和 使用 uic 生成的 ui\_hello.h ,里面定义了一个类 HelloUIWidget 。HelloUIWidget 从 QWidget、Ui::Form 两个基类继承而来,都是 public 继承方式。由于基类有一个是 Qt 窗口类 QWidget,所以在类定义开始处必须加入 Q\_OBJECT 宏,用于声明元对象系统。


该类定义了两个公开类型(public)的函数,即构造函数和析构函数。


最后一个是我们自己编写的保护类型(protected)的函数 AdjustLabel,用于调整 label 标签对象的显示效果。使用多重继承或成员变量的方式就容易丰富窗口类的功能,我们在 HelloUIWidget 里添加了 AdjustLabel 函数,当然还可以添加更多的函数。


2. hellouiwidget.cpp 文件内容:



#include "hellouiwidget.h" HelloUIWidget::HelloUIWidget(QWidget *parent) : QWidget(parent) { setupUi(this); //必须先调用setupUi 函数 //TODO: AdjustLabel(); } HelloUIWidget::~HelloUIWidget() { //无需手动删除 Label 组件和 widget 组件,它们会被 Qt 自动删除 } void HelloUIWidget::AdjustLabel() { label->setText("C语言中文网"); }

HelloUIWidget 构造函数定义处,它使用输入参数 parent 初始化了基类 QWidget,另一个基类 Ui::Form 因为它构造函数不需要参数,就没必要手动编写初始化代码,C++ 编译器自己会先构造好基类。


HelloUIWidget 从基类 Ui::Form 继承了 setupUi 函数,所以可直接调用该函数为自己窗口(this)构建图形界面。在构建好图形界面的控件之后,我们再调用自己编写的 AdjustLabel 函数修改标签控件显示效果。


第二个函数是 HelloUIWidget 类的析构函数,里面没有实际代码。仔细观察 ui\_hello.h 代码可以发现 label 指针保存的对象是用 new 创建的,而这里我们没有手动 delete 它,因为在 Qt 主窗口关闭时,这些控件会随着主窗口全会被自动销毁,对于控件对象可以不用手动编写 delete 代码。


第三个函数是 AdjustLabel ,这个函数里对 label 指针保存的对象进行处理,label 指针成员变量也是从基类 Ui::Form 继承而来的。AdjustLabel 里面第一句代码:


label->setText(“C语言中文网”);


是设置标签控件显示的文本。


3. main.cpp 文件内容:



#include <QtWidgets/QApplication> #include "hellouiwidget.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); HelloUIWidget *w = new HelloUIWidget(); w->show(); return a.exec(); }


代码内容比较简单,main 函数里第一句创建图形程序的入口对象,第二句创建主界面窗口对象,第三句显示主界面窗口,最后一句进入事件循环直到退出为止。窗口对象会在主窗口关闭时自动销毁,所以没有 手动加 delete 代码。


代码分析完了,接下来就是编译生成目标程序了。


1. 打开 Qt 命令行工具,进入 D:\QtDemo 文件夹:


cd /d D:\QtDemo


2. 用 uic 生成 ui\_hello.h:


uic hello.ui -o ui\_hello.h


3. 用 moc 生成元对象系统代码:


moc hellouiwidget.h -o moc\_hellouiwidget.cpp


因为 ui\_hello.h 头文件里面没有 Q\_OBJECT 宏,所以不需要处理,只给 hellouiwidget.h 生成元对象系统代码就够了。


4. 生成可执行程序:


g++ moc\_hellouiwidget.cpp hellouiwidget.cpp main.cpp -std=c++0x -I"D:\Qt\5.9\mingw53\_32\include" -L"D:\Qt\5.9\mingw53\_32\lib" -lQt5Core -lQt5Gui -lQt5Widgets -o main


5. 输入`main.exe`命令就可以运行生成的程序了。


![生成可执行程序的整个流程](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/9ecabf26f4684c13bafdf7b3ba283f84~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5py65Zmo5a2m5Lmg5LmL5b-DQUk=:q75.awebp?rk3s=f64ab15b&x-expires=1771252551&x-signature=DZOjAAzz29LVLQDaQIb2YWPbk5k%3D)



### 用 qmake 生成程序


上面通过自己用 uic、moc、g++ 命令生成目标程序,需要执行的命令是比较多的。之所以费力气讲解编译链接过程的步骤,就是希望读者多了解些知识,如果将来遇上编译或链接时的错误,就可以对号入座,看看大概是哪里出的问题。如果不了解这些过程,可能在编译时少个 ui\_*.h 或 moc\_*.cpp 就会傻眼了。


接着我们介绍傻瓜式的生成方法,就是用 qmake 工具。在开始之前,把 D:\QtDemo 文件夹里面生成的中间文件 ui\_hello.h、moc\_hellouiwidget.cpp、*.o 、*.exe 全删了,保留我们手动编辑的 hello.ui、hellouiwidget.h、hellouiwidget.cpp、main.cpp 四个文件就够了。


1. 打开 Qt 命令行工具,进入 D:\QtDemo 文件夹:


cd /d D:\QtDemo


2. 使用 qmake 生成 .pro 项目文件:


qmake -project “QT+=widgets”


`-project`选项就是为当前文件夹里的代码创建项目文件,本例子默认得到的是 QtDemo.pro ,就是文件夹名字加上 .pro


`QT+=widgets`是我们手动给 pro 文件加了一行,添加了 QtWidgets 模块(widgets),pro 文件默认就带有 QtCore(core)和 QtGui(gui)两个模块,不需要手动添加 core 和 gui 。


3. 使用 qmake 生成 Makefile:


qmake


不带选项和参数的 qmake 默认就是为项目生成 Makefile,运行之后会在项目文件夹里生成 debug 和 release 两个文件夹,以及 Makefile、Makefile.Debug、Makefile.Release 三个生成脚本文件。


4. 使用 make 工具生成目标程序:


mingw32-make all


这条命令会把调试版和发行版的目标程序全都生成。


5. 运行生成好的目标程序:  
 Debug 调试版本程序:


debug\QtDemo.exe


Release 发行版本程序:


release\QtDemo.exe


运行效果就不重复展示了,和前面的是一样的。


可见用 qmake 生成目标程序就是傻瓜式的三板斧:


* 先用 qmake -project 生成项目 pro 文件;
* 再直接用 qmake 生成 Makefile;
* 最后 make all 。


qmake 把许多 uic、moc、g++ 编译链接过程的命令都自动生成了,全放在 Makefile 脚本里,用起来就特别省事。qmake 创建的各种自动生成命令要比我们自己之前编的命令更为科学合理,感兴趣的读者可以记录一下 mingw32-make 命令执行时命令行里出现的各种生成命令,这些命令都类似于以后的 QtCreator 集成开发环境里面生成程序用的命令。


因为本节引入了 ui 文件,我们来看看本节 pro 文件与《[使用qmake工具提升效率]( )》中的有哪些变化:




> 

> ######################################################################  

>  # Automatically generated by qmake (3.1) Wed Jun 5 13:55:11 2019  

>  ######################################################################

> 

> 

> QT+=widgets  

>  TEMPLATE = app  

>  TARGET = QtDemo  

>  INCLUDEPATH += .

> 

> 

> # The following define makes your compiler warn you if you use any  

>  # feature of Qt which has been marked as deprecated (the exact warnings  

>  # depend on your compiler). Please consult the documentation of the  

>  # deprecated API in order to know how to port your code away from it.  

>  DEFINES += QT\_DEPRECATED\_WARNINGS

> 

> 

> # You can also make your code fail to compile if you use deprecated APIs.  

>  # In order to do so, uncomment the following line.  

>  # You can also select to disable deprecated APIs only up to a certain version of Qt.  

>  #DEFINES += QT\_DISABLE\_DEPRECATED\_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0

> 

> 

> # Input  

>  HEADERS += hellouiwidget.h  

>  FORMS += hello.ui  

>  SOURCES += hellouiwidget.cpp main.cpp

> 

> 

> 



《[使用qmake工具提升效率]( )》中例子没有 hello.ui 文件,本节多的 hello.ui 在 pro 文件里就是对应倒数第二行:


FORMS += hello.ui


这句意思就是添加一个构建窗体的 hello.ui 文件,qmake 生成的 Makefile 脚本会自动将 hello.ui 转换成 ui\_hello.h,也会自动为 hellouiwidget.h 生成 moc\_hellouiwidget.cpp ,为开发人员省了很多事。


![img](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/5b62026ddb8b4f90b4017e1d5247ef73~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5py65Zmo5a2m5Lmg5LmL5b-DQUk=:q75.awebp?rk3s=f64ab15b&x-expires=1771252551&x-signature=O2ykVhD5n2Kq2o4R9ZvD4z9kDOM%3D)
![img](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/bb1ec18d721b4f15829adf24e3a64b0b~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5py65Zmo5a2m5Lmg5LmL5b-DQUk=:q75.awebp?rk3s=f64ab15b&x-expires=1771252551&x-signature=5P8005iP34ec5ywef2ef4r8GYjM%3D)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://gitee.com/vip204888)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**