QT开发---基础介绍及环境搭建
QT 基础概述
Qt 是一个跨平台的 C++ 应用程序开发框架,主要用于开发图形用户界面(GUI)程序,同时也支持开发命令行界面(CUI)程序,也支持非 GUI 程序开发。它以其强大的功能和跨平台特性,成为桌面应用程序和嵌入式开发的首选工具。
发展历史
-
起源(1991-1996)
Qt 由挪威程序员 Haavard Nord 和 Eirik Chambe-Eng 于 1991 年开始开发,初衷是为了简化跨平台 GUI 开发。1994 年,两人成立 Trolltech 公司(原名 Quasar Technologies),并于 1996 年发布 Qt 1.0,首次实现了在 Windows、macOS 和 Linux 上的跨平台运行,核心创新是 “信号与槽” 机制。
-
早期发展与开源化(1998-2008)
- 1998 年,为适应 Linux 生态,Trolltech 发布 Qt 的开源版本(基于 QPL 协议),推动了 KDE 桌面环境的诞生(KDE 最初基于 Qt 开发)。
- 2000 年,Qt 引入 Unicode 支持和更完善的跨平台 API,版本迭代至 Qt 2.x、3.x,逐步成为 Linux 平台主流 GUI 框架。
- 2005 年,Qt 4.0 发布,采用模块化架构,引入 Qt Designer 可视化设计工具,支持嵌入式系统和移动设备(如 Symbian)。
- 2008 年,Trolltech 被诺基亚(Nokia)以 1.5 亿欧元收购,Qt 成为诺基亚智能手机系统(Symbian、MeeGo)的官方开发框架。
-
所有权变更与转型(2011-2014)
- 2011 年,诺基亚放弃 MeeGo 转向 Windows Phone,将 Qt 业务出售给芬兰公司 Digia。
- 2012 年,Digia 成立独立子公司 The Qt Company,专注 Qt 开发,并推动其向移动(iOS/Android)和嵌入式领域扩展。
- 2013 年,Qt 5.0 发布,基于 C++11 重构,引入 Qt Quick(QML 语言)用于快速开发现代 UI,支持 OpenGL ES 和硬件加速渲染。
-
持续发展与生态壮大(2015 - 至今)
- 2016 年,Qt 加入 The Qt Group(由 Digia 重组而成),进一步商业化,同时维护开源版本(LGPL 协议)。
- 2020 年,Qt 6.0 发布,基于 C++17,优化图形渲染(如 Qt Quick 3D)、增强跨平台兼容性,并引入模块化构建系统。
- 近年来,Qt 持续拓展在嵌入式(车载、工业控制)、物联网等领域的应用,同时完善对现代操作系统(如 Windows 11、macOS Ventura)的支持。
QT 的核心特点
-
跨平台性
支持 Windows、macOS、Linux、iOS、Android 等多种操作系统,开发者只需编写一次代码,即可在不同平台上编译运行,大大降低了跨平台开发的成本。
-
面向对象与模块化
基于 C++ 实现,同时扩展了信号与槽(Signals & Slots)机制,简化了对象间的通信,比传统的回调函数更灵活。框架分为多个模块(如 GUI、Network、Multimedia 等),可按需使用。
-
丰富的 UI 组件
提供大量预定义的界面控件(如按钮、文本框、表格、树状视图等),支持自定义控件,且支持样式表(QSS)美化界面,类似 CSS。
-
多领域应用支持
- 桌面应用:如 Adobe Photoshop Elements、Autodesk Maya 部分功能依赖 QT。
- 嵌入式开发:广泛用于智能设备、车载系统、工业控制界面。
- 移动应用:可开发 iOS 和 Android 应用。
- 其他:如数据库操作(QSql)、网络编程(QNetwork)、多媒体处理(QMedia)等。
-
开发工具
配套 IDE Qt Creator,集成了代码编辑、编译、调试、UI 设计(Qt Designer)等功能,简化开发流程。
QT安装
https://www.qt.io/download-open-source
向下一直滚动鼠标
点击Download
根据操作系统选择
进入QT安装目录,cmd
.\qt-online-installer-windows-x64-4.9.0.exe --mirror https://mirrors.ustc.edu.cn/qtproject
注:根据自己所下载的版本进行操作
注册QT账户,登录账户,完成安装步骤
创建QT项目
点击选择,创建项目名称和项目路径
选择“CMake”
注意:如果CMake构建项目失败,修改配置
如果不存在CMake,更新组建件
项目创建完成
检查项目是否创建成功---点击运行,观察是否出现MainWindow窗口
QT工程文件解析
项目大体框架
CMakeLists.txt
在 Qt 开发中,CMakeLists.txt
是使用 CMake 构建系统时的核心配置文件,用于定义项目结构、编译选项、依赖库等信息。对于 Qt 项目,CMakeLists.txt
会结合 Qt 特有的 CMake 模块(如 FindQt5.cmake
或 Qt6Config.cmake
)来简化 Qt 库的引入和处理(如 MOC、UIC、RCC 等预编译步骤)。
CMakeLists.txt
通过定义项目结构、依赖模块和编译规则,使 CMake 能够自动构建 Qt 项目,包括处理 Qt 特有的预编译步骤。合理配置可确保项目在不同平台(Windows/macOS/Linux)上的一致性编译,是 Qt 跨平台开发的重要工具
cmake_minimum_required(VERSION 3.16) //指定构建该项目所需的最低 CMake 版本为 3.16project(QTproject01 VERSION 0.1 LANGUAGES CXX) //定义项目名称//Qt 自动处理配置
set(CMAKE_AUTOUIC ON) //自动调用 uic 工具处理 .ui 文件(将 Qt Designer 界面转为 C++ 代码)
set(CMAKE_AUTOMOC ON) //自动调用 moc 工具处理带 Q_OBJECT 宏的头文件(生成信号槽元对象代码)
set(CMAKE_AUTORCC ON) //自动调用 rcc 工具处理 .qrc 资源文件(将图片、图标等打包为二进制)//C++ 标准配置
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)//查找 Qt 依赖
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
//查找 Qt 库,优先尝试 Qt6,若找不到则尝试 Qt5(NAMES Qt6 Qt5),并指定必须包含 Widgets(GUI 控件核心模块)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
//根据找到的 Qt 主版本(QT_VERSION_MAJOR,值为 5 或 6),再次确认对应版本的 Widgets 模块是否存在//源文件列表
set(PROJECT_SOURCESmain.cppmainwindow.cppmainwindow.hmainwindow.ui
)//生成可执行文件(兼容 Qt 5/6 和平台)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)qt_add_executable(QTproject01MANUAL_FINALIZATION${PROJECT_SOURCES})
# Define target properties for Android with Qt 6 as:
# set_property(TARGET QTproject01 APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
# ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
else()if(ANDROID)add_library(QTproject01 SHARED${PROJECT_SOURCES})
# Define properties for Android with Qt 5 after find_package() calls as:
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")else()add_executable(QTproject01${PROJECT_SOURCES})endif()
endif()//链接 Qt 库
target_link_libraries(QTproject01 PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
//将项目与 Qt 的 Widgets 模块链接(PRIVATE 表示该依赖仅用于当前项目,不传递给其他依赖项)Qt${QT_VERSION_MAJOR}::Widgets 会自动适配 Qt 5 或 6 的库# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.//平台特定属性(macOS/Windows/iOS)
if(${QT_VERSION} VERSION_LESS 6.1.0)set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.QTproject01)
endif()
set_target_properties(QTproject01 PROPERTIES${BUNDLE_ID_OPTION}MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}MACOSX_BUNDLE TRUEWIN32_EXECUTABLE TRUE
)//安装配置
include(GNUInstallDirs)
install(TARGETS QTproject01BUNDLE DESTINATION .LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
/*
定义安装规则:
GNUInstallDirs:引入标准安装路径(如 Linux 下的 /usr/bin)
根据目标类型(bundle、库、可执行文件)安装到对应目录(适用于 make install 等命令)*///Qt 6 最终化配置
if(QT_VERSION_MAJOR EQUAL 6)qt_finalize_executable(QTproject01)
endif()
//Qt 6 特有的最终化步骤,用于完成平台相关的额外配置(如 macOS 签名、iOS 打包等),Qt 5 不需要此步骤
可以在界面最左列"帮助"按键中查询项目中使用的相关类 ----文档页面
QT中半自动管理内存的机制
在 Qt 中,内存管理的核心机制是基于对象树(Object Tree) 和父子关系的半自动管理方式,主要通过 QObject
类实现。这种机制既避免了完全手动管理内存(如频繁 new/delete
导致的泄漏或双重释放),又不像垃圾回收(GC)那样完全自动(仍需开发者建立合理的对象关系),因此称为 “半自动”。
核心原理:对象树与父子关系
-
对象树的概念
Qt 中,所有继承自
QObject
的类(几乎所有 Qt 核心类,如QWidget
、QTimer
、QNetworkAccessManager
等)都可以加入一个 “对象树”。当一个对象被指定为另一个对象的 “父对象” 时,子对象会被添加到父对象的内部列表中,形成层级关系(类似树形结构)。 -
父子关系的建立
建立父子关系有两种方式:
- 构造函数中指定:创建子对象时,将父对象作为参数传入构造函数,eg:
QPushButton *button = new QPushButton("Click me", parentWidget);
- 调用
setParent()
方法:事后通过child->setParent(parent)
关联。
- 构造函数中指定:创建子对象时,将父对象作为参数传入构造函数,eg:
-
自动销毁机制
当父对象被销毁(调用
delete
或生命周期结束)时,会自动遍历其维护的子对象列表,逐个调用delete
销毁所有子对象;同时,子对象被销毁前会自动从父对象的列表中移除,避免父对象再次操作已销毁的子对象。这个过程是递归的:父对象销毁子对象,子对象作为父对象再销毁其 own 的子对象,直到整个对象树的叶子节点被清理。
优势:简化内存管理
- 减少手动
delete
:对于有明确归属关系的对象(如窗口中的按钮、对话框中的输入框),只需确保根节点(如顶层窗口)被正确销毁,整个对象树会被自动清理,无需手动删除每个子对象。 - 避免内存泄漏:只要对象树关系合理,不会因遗漏
delete
导致内存泄漏。 - 防止双重释放:子对象被父对象销毁后,不会再被其他地方重复
delete
(子对象销毁时会自动脱离父对象列表)。
注意事项(“半自动” 的体现)
-
非
QObject
派生类不适用只有继承自
QObject
的类才支持对象树机制。对于普通 C++ 类(如std::string
、自定义非QObject
类),仍需手动管理内存或使用智能指针(如std::unique_ptr
)。 -
无父对象的
QObject
需要手动销毁如果一个
QObject
没有父对象(如独立的工具类实例),Qt 不会自动销毁它,必须手动调用delete
,否则会导致内存泄漏。 -
避免循环引用
若两个
QObject
互相设置为父对象(循环引用),会导致对象树无法正常销毁(双方都等待对方先销毁),造成内存泄漏。 -
堆对象而非栈对象
Qt 的对象树机制通常用于堆上创建的对象(
new
分配)。若将栈对象设为另一个对象的子对象,可能导致程序崩溃(栈对象销毁时,父对象可能再次尝试删除它)。
结语:
无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力