Qt 项目代码解释(4)
文章目录
- 初创建项目代码解释
- main.cpp
- widget.h
- widget.cpp
- widget.ui(关键点)
- Qt_design_2.pro
- 生成的额外文件
简介:该篇文章主要介绍的是当我们创建项目成功后,其自动创建的各文件代码的含义,这有助于理解其创建图形化界面的底层逻辑,为后续独立创建项目作铺垫。这些内容说重要也重要,说不重要也不重要,不过我觉得可以尝试去理解理解,最后祝大家五一放假快乐~~
初创建项目代码解释
创建一个项目后,有五个文件需要逐一进行分析,弄懂它们的的大概意思
main.cpp
#include "widget.h"#include <QApplication>int main(int argc, char *argv[]) // main的形参就是命令行参数
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}
- 如果要编写一个Qt的图形化界面程序就一定需要有
QApplication对象(即 QApplication a(argc, argv) )
Widget w;
这里Widget是创建项目时填写的类名(Class name
),这一步就是去创建一个控件对象,而w.show
就是让这个控件对象显示出来,w.hide()
就是隐藏这个控件对象return a.exec();
它则是让程序执行起来- 还记得创建项目时有一个基类
QWidget
,它是Widget的父类,show 和 hide 方法则是由父类提供的
这里要注意一下:之前在Linux中也学过六个函数(本质上是一个),叫做exec.进程程序替换,把可执行文件中的代码和数据替换到当前进程中,而当前 Qt中的 exec和Linux中的exec没有任何关系,只是名字恰好是一样的。这样的设定挺常见的,计算机中经常会有一个术语,在不同的场合下,表示的含义不一样,这就需要结合上下文来进行理解。比如啥叫 栈,啥叫 堆,数据结构中的栈/堆,还是操作系统,虚拟地址空间栈/堆,还是JVM 中的栈/堆,这几种完全是不同的
widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; } // 类的声明
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private:Ui::Widget *ui; // 和form file密切相关,这里不讨论
};
#endif // WIDGET_H
#ifndef WIDGET_H & #define WIDGET_H
,它们的作用是保证头文件只被包含一次,更推荐这种写法:#pragma once
Q_OBJECT
它是一个Qt内置的宏,宏本质是文本替换,而它展开后就会生成一大堆代码,这是因为Qt中有一个非常核心的机制,即 “信号” 和 “槽”。如果某个类想去使用这个 “信号” 和 “槽” 就需要引入Q_OBJECT
这个宏class Widget : public QWidget
这个QWidget就是我们创建项目时选择的父类,它是Qt SDK内置的,如果想要去使用这个类,就得包含对应的头文件#include <QWidget>
。这里要补充一点,按照Qt的设定所使用Qt中内置的类,其类名和头文件的类名是一致的
,当然也不是所有用到Qt的类都需要去显示包含头文件,在C++中头文件可能是 “间接包含” 的
,比如你显示包含头文件 a.h,而头文件a.h中又包含b.h,那只引入a.h就已经包含头文件a.h 与 b.h,所以后续写代码时,可能不知道到底要包含多少个头文件,哪些头文件中又间接包含了什么头文件,那就先将这个Qt的类先拿过来用,如果这个类提示找不到定义,那就没有间接包含需要我们手动的显示把对应的头文件给包含一下即可Widget(QWidget *parent = nullptr);
在Qt中引入了对象树的机制,此处的对象树就是一棵普通的N叉树(不是二叉树),其一个结点可能有N个孩子结点,但一定只能有一个父结点。因此这段代码的意思就是,创建的这个对象可以把它挂到对象树上,挂的过程就是给它指定父结点的过程
widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);
}Widget::~Widget()
{delete ui;
}
#include "ui_widget.h"
,form file被qmake生成的头文件ui->setupUi(this);
将form file生成的图形化界面和当前的widget关联起来,关键点在于这个form file
文件
widget.ui(关键点)
双击widget.ui
文件,此时Qt Creator就会去调用Qt Designer打开ui文件,出现图形化的界面编辑器
此时再点左侧边栏的编辑按钮,就会显示
.ui
的本体内容了
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>Widget</class><widget class="QWidget" name="Widget"><property name="geometry"><rect><x>0</x><y>0</y><width>1255</width><height>600</height></rect></property><property name="windowTitle"><string>Widget</string></property></widget><resources/><connections/>
</ui>
- 首先这个格式被称为
xml格式
,它既有成对的标签(<ui...> ... </ui>
),也有单标签(<resources/>
)等等 - 这里的
xml格式
与html
格式非常的类似,都是使用成对的标签来表示数据,xml这里的标签,有哪些标签,都表示什么含义,都是程序员自己去人为定义的,而我们此处看到的这些标签都是开发Qt的大佬们自己决定的,那这里标签它们的具体含义我们无需关注,只需要知道 widget.ui文件本质上是一个xml
即可,而html
虽然也是通过标签来表示,但html的标签都是固定的,每个标签是啥含义,都有一个专门的标准委员会约定的,每个浏览器都是按照同样的规则去解释 - Qt中使用的xml文件就是去描述程序的界面是啥样的,进一步qmake就会调用相关的工具,依据这个xml文件生成一些C++代码,从而把完整的界面构造出来
-
以下是随便找的网页源代码
Qt_design_2.pro
.pro后缀
是Qt项目的工程文件,也是qmake工具构建的重要依据
QT += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked 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 it uses 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.0SOURCES += \main.cpp \widget.cppHEADERS += \widget.hFORMS += \widget.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
QT += core gui
要引入的Qt模块,后面学习到一些内容时可能会修改这里- 下面的代码片段描述了当前项目中参与构建的文件都有哪些,即编译器需要去编译哪些文件,这个地方无需我们手动修改,Qt Creator会帮我们自动维护好
SOURCES += \main.cpp \widget.cppHEADERS += \widget.hFORMS += \widget.ui
- .pro类似于Linux中的 Makefile文件(自动化编译),qmake搭配 .pro 起到的作用就和
Makefile
是类似的。只不过Qt Creator把这个过程中编译的细节都已经封装好,无需过多关注,只需要我们直接点击运行按钮就能直接编译运行
生成的额外文件
上面生成的 .h,.cpp,.ui,.pro文件都是源代码,如果编译运行Qt项目,构建过程中还会生成一些中间文件。鼠标放到左边栏框中的任意一个文件,右键点
在Explorer(文件管理器)中显示
,再退回到上一步路径会发现多出来一个 “build-xxxx" 目录,那这个目录里面就是该项目运行过程中,生成的一些临时文件
双击点进去后会看到如下内容,由此看到这个编译Qt程序也会用到
Makefile
,只不过这个 Makefile 无需手动写,而是qmake帮我们自动生成的。而这个ui_widget.h
它是由xml
生成的.h文件,也是在widget.cpp
中所包含的头文件
当点进debug目录会看到有个可执行程序(exe),而这个程序就是最终生成的可执行程序,如果直接运行效果就跟之前在 Qt Creator中运行出来的窗口相同
下面是
Ui_Widget.h
头文件的主体代码,你将文件widget.h
与widget.cpp
结合起来看,widget.h 与 widget.cpp 声明和定义分离,其子类Widget的构造函数在完成初始化的同时会去调用父类的setupUi
函数去生成界面的具体细节
// widget.cpp
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);
}
// Ui_Widget.h
class Ui_Widget
{
public:void setupUi(QWidget *Widget){if (Widget->objectName().isEmpty())Widget->setObjectName(QString::fromUtf8("Widget"));Widget->resize(1255, 600);retranslateUi(Widget);QMetaObject::connectSlotsByName(Widget);} // setupUivoid retranslateUi(QWidget *Widget){Widget->setWindowTitle(QCoreApplication::translate("Widget", "Widget", nullptr));} // retranslateUi};namespace Ui {class Widget: public Ui_Widget {};
} // namespace Ui