公司动态
初识Qt——创建第一个Qt项目
1.Qt环境搭建Qt开发环境需要安装3个部分1. C编译器gcc,cl.exe...)。Qt SDK中也会有需要在安装过程中勾选上。2. Qt SDK ——软件开发工具包。Windows版本的Qt SDK 里已经内置了C编译器内置的编译器是mingwWindows版本的gcc/g。要是想用VS内置的cl.exe作为编译器需要配置很多额外的东西容易出错这里就不做介绍了。3. 需要有一个Qt的集成开发环境IDE。1Qt 官方的Qt Creator——最容易入门容易上手Qt SDK 中也有2Visual Studio——功能更强但是需要额外的配置容易出错。有些公司开发商业Qt程序的时候可能会使用VS3Eclipse——并非只是Java IDE其本身是一个IDE平台可以搭配不同的插件构成不同的IDE虽然理论上来说是应该有三个东西但其实只要安装一个Qt SDK另外两个也就都有了。安装Qt SDKTry Qt | Develop Applications and Embedded Systems | Qt这是Qt SDK在线安装器下载的位置官方推荐的方法Index of /official_releases/qt这个是离线安装包现在的位置但是只有Qt6版本Index of /archive/qt 这里包含了Qt5在线安装器这是官方推荐的方式。你需要先下载一个轻量级的安装器。运行后它会让你登录Qt账户然后你可以按需选择安装需要的Qt版本、编译器和模块适合网络稳定的开发者。离线安装包可以直接访问获取完整的离线安装包但体积会比较大可能会下载失败具体的安装教程网上有很多资料大家可以按需查找我这里就不赘述了。大家在成功下载Qt Creator后一定不要忘记把Qt的bin目录加入到Path环境变量中2. 创建第一个Qt项目下载好Qt Creator之后我们就可以开始创建第一项目了我下载的是Qt5.15.2创建新项目左侧我们选择Application(Qt)就是使用C语言写一个GUI程序。我们常使用的是传统的开发GUI方式Qt Widgets Application一个使用 C 和 Qt Widgets 构建的传统桌面应用程序。Qt Quick Application (Qt)使用 QML 语言 和 C 混合编程的现代应用程序。界面用 QML一种类似 JSON 的声明式语言编写逻辑用 C 实现。Qt Quick Application (compat)兼容模式 的 Qt Quick 项目用于支持旧版本 Qt Quick 的语法和模块。Qt Console Application创建控制台命令行程序没有图形界面。点击选择后就会来到这个界面这里可以修改项目名称以及项目路径然后点击下一步这里要选择构建系统Qt 构建系统就是一套将你的源代码.cpp / .h / .qml / .ui 等编译、链接成最终可执行程序.exe / .app的自动化工具和规则集合。qmakeQt 自带的专用构建工具配置文件.pro文件语法对 Qt 开发者很友好生成 Makefile再调用 make 等工具执行编译我们选择这个Cmake行业标准的通用跨平台构建系统配置文件CMakeLists.txt文件功能强大但语法稍复杂生成平台原生的构建文件如 Makefile再调用编译QbsQt 曾推出的下一代全功能构建工具配置文件.qbs文件基于 JavaScript 的声明式语法一体化工具直接生成依赖图并执行构建跳过了生成 Makefile 的中间步骤但是现在官方已经没有在维护了使用QtCreator 创建项目会自动的生成一些代码出来生成的代码就包含一个类此处就是要选择这个自动生成的类的父类是谁。QMainWindows —— 完整的应用程序窗口(可以包含菜单栏工具栏状态栏...)QWidget —— 表示一个控件.(窗口上的一个具体的元素.输入框按钮下拉框单选按钮复选按钮....)。我们选择这个QDialog —— 表示一个用于短暂交互的对话框注意这里的Generate form勾选后创建一个form file这个form file 非常关键Qt中创建图形化界面的程序有两种方式.1.直接通过c代码的方式创建界面.2.通过form file,以图形化的方式来生成界面.有了这个form file就可以使用 Qt Designer 或者直接使用 Qt Creator 来编辑这个ui 文件从而以图形化的方式快速方便的生成图形界面。这里是选择翻译文件和对应的翻译语言让项目可以国际化这里我们先不考虑。这里是选择一下基于哪个编译器的QtSDK来构建后续代码按需选择即可选择完成即可3. 详解项目初始代码创建好项目后我们会发现项目初始状态下就有一些代码文件3.1 main.cpp//main.cpp #include widget.h #include QApplication int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return QApplication::exec(); }这是main.cpp文件中的内容main的形参就是命令行参数编写一个Qt 的图形化界面程序一定要有且只有一个QApplication 对象QApplication a(argc, argv); —— 这行代码就是创建一个 QApplication对象命名为 aWidget w; —— 这个Widget对象w代表应用程序的主窗口w.show(); —— 调用 Widget对象的show() 方法让窗口显示在屏幕上。show方法是非阻塞的它调用后立即返回不会卡在这里等待窗口关闭。return QApplication::exec(); —— 启动 Qt 的事件循环Event Loop并进入阻塞状态直到应用程序退出。事件循环是 GUI 程序的“心脏”它不停地从系统消息队列里取事件鼠标点击、键盘按键、定时器超时、窗口重绘等并分发给对应的窗口去处理。3.2 widget.h//widget.h #ifndef WIDGET_H #define WIDGET_H #include QWidget QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent nullptr); ~Widget() override; private: Ui::Widget *ui; }; #endif // WIDGET_H#ifndef WIDGET_H#define WIDGET_H防止头文件被重复包含也可以用#pragma once替代QT_BEGIN_NAMESPACEnamespace Ui {class Widget;}QT_END_NAMESPACE声明一个名为Ui::Widget的类但这个类不在当前文件中定义它的定义在ui_widget.h中由 UIC 编译器从.ui文件自动生成。这是一种前置声明告诉编译器“Ui::Widget这个类存在但具体定义你稍后再去找”。这样可以在widget.h中声明Ui::Widget *ui;指针而不需要 #includeui_widget.h从而减少编译依赖加快编译速度。class Widget : public QWidget这里继承的QWidget是在创建项目时选择的父类Q_OBJECT这是 Qt 的元对象编译器的标记宏。任何需要信号与槽功能的类都必须把这个宏放在类的最开始private区域之前。它会展开成一系列元对象代码让这个类支持 Qt 的反射机制。explicit Widget(QWidget *parent nullptr);~Widget() override;构造函数和析构函数声明。explicit是防止隐式类型转换parent nullptr默认父指针为空。如果传入了父对象Qt 的内存管理机制会让父对象在销毁时自动销毁子对象。析构函数用override关键字明确表示这是重写基类QWidget的析构函数同时必须在这里释放ui指针。private:Ui::Widget *ui;这个ui指针是连接C 代码和 .ui界面文件的桥梁。所有的界面控件按钮、标签、输入框等都通过 ui-控件名 来访问。3.3 widget.cpp//main.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; }Widget::Widget(QWidget *parent): QWidget(parent) // 调用基类 QWidget 的构造函数传入 parent, ui(new Ui::Widget) // 初始化 ui 指针创建一个 Ui::Widget 对象{ui-setupUi(this); // 调用 setupUi将界面布局和控件“安装”到当前窗口上}Widget::~Widget(){delete ui;}因为ui是用new动态分配的如果不手动delete释放ui指针指向的内存会导致内存泄漏ui指向的对象不是Qt对象树中的一员所以不会自动释放3.4 界面文件在Qt中.ui 文件是使用Qt Widgets Designer这个可视化设计工具生成的界面定义文件。它的核心作用就是让你能用“所见即所得”的拖拽方式设计界面从而更加方便我们设计界面布局。双击这个界面文件就可以来到这个界面在这个界面中就可以拖拽控件进行页面设计了。4. 创建HelloWorld按钮现在我们已经大致了解了项目的结构现在我们来试着创建一个hello world按钮拖拽过来后可以调整按钮的各种属性我们把按钮上的显示内容可以改为HelloWorld运行结果如下图所示我们也可以通过代码来实现://widget.cpp #include widget.h #include ui_widget.h #include QPushButton //包含相关的头文件 Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui-setupUi(this); QPushButton* hw new QPushButton(this);//创建一个按钮并且挂到对象树上 hw-setText(HelloWorld);//设置按钮上显示的文字 } Widget::~Widget() { delete ui; }这样编写代码之后也可以在界面上实现一个HelloWorld按钮5. 对象树Qt对象树是一个基于QObject类的、通过父子关系组织起来的树形数据结构。在纯C中你需要记住每个new出来的对象在何时delete。在复杂的GUI程序中控件之间层层嵌套手动管理极易出错。Qt对象树解决这个问题的思路是一个对象的所有权归它的父对象所有。父对象销毁时递归地销毁所有子对象。这意味着你只需要管理根节点的生命周期——当根节点被销毁时整棵树自动清理。这极大地降低了内存泄漏的风险。前面我们用代码new了一个QPushButton对象出来就通过this指针挂到对象树上了所以可以不用手动释放。6. 认识Qt坐标系说到坐标系我们第一时间可能想到的是数学中的坐标系y轴向上——右手坐标系但是在计算机世界中的坐标系一般是这种y轴向下——左手坐标系在Qt中坐标原点一般是屏幕左上角或者窗口左上角给Qt的某个控件设置位置就需要指定坐标.对于这个控件来说坐标系原点就是父窗口/控件的左上角。我们用代码生成的按钮位置默认就是原点我们可以通过move这个函数来设置按钮的位置单位是像素