Qt开发环境搭建与核心机制详解:从入门到实战排错
在实际 C++ 项目开发中,尤其是涉及图形用户界面(GUI)时,Qt 框架因其跨平台、功能丰富和面向对象的特性,成为许多开发者的首选。然而,从零开始搭建一个稳定、高效的 Qt 开发环境,并理解其核心机制,常常会遇到诸如环境配置失败、信号槽连接无效、中文乱码、部署依赖缺失等一系列问题。这些问题不仅消耗时间,也容易让初学者感到挫败。
本文旨在为希望系统学习 Qt 的 C++ 开发者提供一份从环境搭建到核心概念,再到实战排错的完整指南。无论你是刚接触 Qt,还是希望梳理已有知识,都能通过本文构建一个清晰、可复现的学习路径。我们将从 Qt 的基本概念和工作原理讲起,然后逐步完成开发环境的安装与配置,接着通过一个最小化的窗口程序来实践 Qt 的核心编程模型,最后深入探讨开发中常见的陷阱及其解决方案。学完后,你将能够独立搭建 Qt 开发环境,理解并运用信号槽机制,并具备排查常见 Qt 开发问题的能力。
1. 理解 Qt:不仅仅是 GUI 框架
在开始安装和编码之前,有必要澄清 Qt 究竟是什么,以及它如何工作。这有助于理解后续配置步骤背后的逻辑,并在遇到问题时能进行有效推理。
1.1 Qt 的核心构成与跨平台原理
Qt 是一个完整的应用程序开发框架,而不仅仅是一个 GUI 库。它提供了从界面设计、网络通信、数据库访问、多线程到 XML 处理等全方位的支持。其核心价值在于“一次编写,到处编译”。Qt 通过抽象层来实现跨平台:你的代码调用的是 Qt 的 API(如QWidget,QNetworkAccessManager),而 Qt 内部则根据当前编译的目标平台(Windows, Linux, macOS 等),调用对应的原生系统 API(如 Win32 API, Cocoa, X11)来执行具体操作。
这种设计意味着,在开发阶段,你需要 Qt 的开发库(头文件和链接库)以及配套的构建工具(如 qmake 或 CMake)。而在部署阶段,目标机器上需要存在对应平台的 Qt 运行时库(DLL, .so, .dylib 等),你的应用程序才能正常运行。这也是为什么直接拷贝一个在开发机上编译好的 Qt 程序到另一台没有 Qt 环境的机器上,常常会弹出类似“无法找到 Qt5Core.dll”或“no Qt platform plugin could be initialized”错误的原因。
1.2 Qt 与 MFC、WPF 等框架的本质区别
从网络热词中可以看到“qt 是不是mfc架构”的疑问。这反映了初学者对 GUI 框架分类的困惑。MFC(Microsoft Foundation Classes)是微软为 Windows 平台提供的 C++ 类库,它紧密绑定 Win32 API,本质上是对 Windows 消息循环和窗口过程的一种 C++ 封装。它不具备跨平台能力。
Qt 虽然也是 C++ 框架,但其设计哲学是“面向对象”和“跨平台”。它使用了一套自有的元对象系统(Meta-Object System)来支持信号槽机制和运行时类型信息,这是 Qt 最核心的特性之一,也是其与标准 C++ 和 MFC 最大的不同。因此,Qt 不是 MFC 架构,它是一个更现代、更独立、功能更全面的框架。WPF 则是基于 .NET 的框架,与 C++/Qt 属于不同的技术栈。
1.3 Qt 的授权模式选择
Qt 提供两种主要授权:开源版(LGPL/GPL)和商业版。对于个人学习者、开源项目或某些特定商业应用,使用开源版是常见选择。在下载安装 Qt 时,安装程序会引导你注册一个 Qt 账户(免费),并选择要安装的组件。理解授权条款对于商业应用开发至关重要,但学习阶段使用开源版没有问题。
2. 搭建高效的 Qt 开发环境
一个配置正确的开发环境是高效学习的前提。本节将详细讲解在 Windows 系统下,使用 Qt 官方安装器搭配 Visual Studio 或 MinGW 编译器,以及使用 VS Code 作为轻量级编辑器的完整配置流程。Linux 和 macOS 的流程在思路上类似,主要区别在于包管理器和编译工具链。
2.1 安装前的准备工作:编译器与调试器
Qt 本身不包含 C++ 编译器,它需要依赖外部的工具链。在 Windows 上,主要有两个选择:
- MSVC (Microsoft Visual C++):需要预先安装 Visual Studio(如 VS 2019/2022)或独立的 Visual Studio Build Tools。这是与 Windows 系统集成度最高的方案,调试体验好。
- MinGW-w64:一个 Windows 上的 GCC 移植版本。Qt 官方安装包通常自带一个特定版本的 MinGW。它的优点是生成的可执行文件依赖较少的运行时库,部署相对简单。
对于初学者,如果你的机器上没有 Visual Studio,选择 Qt 安装包自带的 MinGW 是最快捷的方式。如果你已经安装了 Visual Studio,那么选择对应的 MSVC 版本可以获得更好的性能和支持。
检查 MSVC 环境:打开“开发者命令提示符 for VS 2022”,输入cl,如果显示编译器版本信息,则说明 MSVC 可用。
检查 MinGW 环境:打开命令提示符,输入g++ --version,如果显示 GCC 版本信息,则说明 MinGW 已配置在 PATH 中。
2.2 使用 Qt 官方在线安装器
这是最推荐的方式,可以灵活选择组件和版本。
下载安装器:访问 Qt 官网,下载 Qt 在线安装程序。运行安装程序,使用 Qt 账户登录。
选择安装路径:建议选择一个不含中文和空格的路径,例如
D:\Qt。选择组件:这是最关键的一步。组件分为几个部分:
- Qt 版本:例如
Qt 5.15.2,Qt 6.5.0等。建议初学者选择最新的长期支持(LTS)版本,如 Qt 6.2 LTS 或 Qt 5.15 LTS,它们更稳定。 - 编译器:根据你的准备,勾选
MSVC 2019 64-bit或MinGW 8.1.0 64-bit。至少要选一个。 - 附加工具:务必勾选
Qt Creator,这是 Qt 官方集成开发环境,对 Qt 开发支持最好。同时建议勾选Debugging Tools for Windows(如果使用 MSVC)和MinGW编译器(如果之前没装)。 - 开发者与设计者工具:
Qt Creator已包含。Qt Designer是可视化界面设计工具,它会作为插件集成在 Qt Creator 中,通常不需要单独安装。
一个典型的初学者选择是:
Qt 6.2.4->MSVC 2019 64-bit和MinGW 11.2.0 64-bit->Qt Creator。- Qt 版本:例如
同意许可协议并安装:等待安装完成,这可能需要较长时间,取决于网络速度和所选组件。
安装完成后,你可以在开始菜单或安装目录下找到Qt Creator。
2.3 配置 Qt Creator
首次运行 Qt Creator,需要进行简单配置。
- 配置编译器:进入
工具->选项->Kits->编译器。Qt Creator 通常能自动检测到通过安装器安装的 MSVC 和 MinGW。确认它们已存在。 - 配置 Qt 版本:进入
Qt 版本标签页。Qt Creator 应能自动找到安装的 Qt 版本。如果没有,点击“添加”,选择qmake.exe的路径,通常位于D:\Qt\6.2.4\msvc2019_64\bin\qmake.exe。 - 配置构建套件 (Kits):进入
Kits标签页。这里将编译器、Qt 版本和调试器组合成一个可用的开发环境。确保有一个套件的编译器、Qt 版本和调试器都已正确设置,并且没有黄色警告图标。
2.4 使用 VS Code 作为 Qt 开发环境(可选)
如果你更喜欢 VS Code 的轻量级体验,也可以配置它来开发 Qt。
- 安装 C++ 扩展:在 VS Code 中安装 Microsoft 的
C/C++扩展。 - 安装 CMake 或 qmake:Qt 项目可以用 CMake 或 qmake 构建。确保系统已安装 CMake 并将其添加到 PATH。
- 创建 CMakeLists.txt:在项目根目录创建
CMakeLists.txt,内容示例如下:cmake_minimum_required(VERSION 3.16) project(MyQtApp LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) find_package(Qt6 REQUIRED COMPONENTS Core Widgets) add_executable(MyQtApp main.cpp) target_link_libraries(MyQtApp Qt6::Core Qt6::Widgets) - 配置 VS Code:在项目目录下,按
Ctrl+Shift+P,输入CMake: Configure,选择你的编译器套件(如Visual Studio Community 2022 Release - amd64)。VS Code 会生成构建配置。 - 编写代码与构建:编写
.cpp和.h文件,然后使用 VS Code 底部的 CMake 工具进行构建和调试。
这种方式更适合已经熟悉 CMake 和 VS Code 的开发者,对于 Qt 初学者,Qt Creator 的集成度更高,问题更少。
3. 创建第一个 Qt 窗口程序:理解核心机制
环境就绪后,我们通过一个最简单的窗口程序,来实践 Qt 的核心编程模型。这个程序将展示一个窗口,并演示最基本的信号槽连接。
3.1 使用 Qt Creator 创建新项目
- 打开 Qt Creator,点击
文件->新建文件或项目。 - 选择
Application->Qt Widgets Application,点击Choose。 - 输入项目名称(如
HelloQt)和路径,点击下一步。 - 选择构建套件(Kit),即我们之前配置好的 MSVC 或 MinGW 套件,点击
下一步。 - 在“类信息”页面,基类选择
QMainWindow,类名保持MainWindow,勾选“创建界面”。这将自动生成一个带菜单栏、状态栏的主窗口类和一个对应的.ui界面文件。点击下一步并完成。
Qt Creator 会自动生成以下关键文件:
main.cpp:程序入口。mainwindow.h/mainwindow.cpp:主窗口类的头文件和实现文件。mainwindow.ui:XML 格式的界面描述文件,可以用 Qt Designer 可视化编辑。
3.2 剖析生成的代码:应用程序生命周期
打开main.cpp,你会看到如下代码:
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); // 1. 创建应用程序对象 MainWindow w; // 2. 创建主窗口对象 w.show(); // 3. 显示窗口 return a.exec(); // 4. 进入事件循环 }这是每个 Qt Widgets 应用程序的骨架:
QApplication:管理整个应用程序的资源、设置和事件循环。每个程序有且只有一个。MainWindow:我们自定义的主窗口对象。show():将窗口部件显示在屏幕上。默认是非模态窗口。exec():启动应用程序的事件循环。这个方法会阻塞,直到窗口关闭。事件循环负责监听用户输入、系统事件、定时器等,并调用相应的槽函数。
3.3 添加一个按钮并连接信号槽
现在,我们给窗口添加一个按钮,点击按钮时改变窗口标题。
- 设计界面:在 Qt Creator 的项目文件列表中,双击
mainwindow.ui文件,会打开 Qt Designer。从左侧“部件盒”中拖拽一个Push Button到中间的窗口上。你可以右侧属性编辑器中修改按钮的objectName(如btnTest)和text(如点击我)。保存文件。 - 连接信号与槽:Qt 的核心机制是信号(Signal)和槽(Slot)。信号在某个事件发生时被发射(emit),槽是普通的成员函数,可以被信号触发。我们可以在代码中连接它们。 打开
mainwindow.cpp,在构造函数MainWindow::MainWindow中添加连接代码:#include "ui_mainwindow.h" // 自动生成,包含界面元素的类定义 #include <QMessageBox> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); // 初始化界面,创建我们在 Designer 中拖放的按钮等部件 // 连接信号与槽 // 格式:connect(发送者, 信号, 接收者, 槽函数) connect(ui->btnTest, &QPushButton::clicked, this, &MainWindow::onButtonClicked); } - 实现槽函数:在
mainwindow.h中声明槽函数。在MainWindow类的private slots:区域添加:
然后在private slots: void onButtonClicked();mainwindow.cpp中实现这个函数:void MainWindow::onButtonClicked() { // 改变窗口标题 this->setWindowTitle("按钮被点击了!"); // 或者弹出一个消息框 // QMessageBox::information(this, "提示", "你好,Qt!"); } - 构建与运行:点击 Qt Creator 左下角的绿色三角按钮(或按
Ctrl+R)来构建并运行项目。如果一切顺利,你将看到一个带按钮的窗口,点击按钮,窗口标题会改变。
3.4 理解元对象系统与 moc
你可能注意到,我们在头文件中使用了signals:和slots:关键字,并且槽函数需要声明在slots:区域下。这些都不是标准 C++ 关键字。Qt 使用一个叫做元对象编译器(Meta-Object Compiler,moc)的工具,在编译你的 C++ 代码之前,先处理这些包含Q_OBJECT宏的头文件。
moc会生成额外的moc_*.cpp文件,这些文件包含了信号槽连接、运行时类型信息(RTTI)和动态属性系统所需的代码。这就是为什么 Qt 项目必须使用qmake或CMake(并开启AUTOMOC)来构建,因为它们会自动调用moc工具。如果你手动编译,忘记处理moc,就会遇到“undefined reference to vtable”之类的链接错误。
4. 深入 Qt 核心:信号槽、内存管理与 UI 文件
掌握了基本流程后,我们需要深入几个核心概念,它们是写出健壮 Qt 程序的基础。
4.1 信号槽连接的多种方式与注意事项
上面的例子使用了 Qt5 推荐的基于函数指针的语法connect(sender, &Sender::signal, receiver, &Receiver::slot),这是类型安全的。此外还有旧式语法和 Lambda 表达式方式。
Lambda 表达式连接(非常常用):
connect(ui->btnTest, &QPushButton::clicked, this, [this]() { this->setWindowTitle("使用Lambda"); // 可以访问类的成员变量,但要注意生命周期 });使用 Lambda 时,需要特别注意捕获列表。如果槽函数中需要修改 UI 或访问成员,通常捕获[this]。但要确保在 Lambda 执行时,this对象仍然存活,否则会导致程序崩溃。
连接失败常见原因:
- 对象生命周期问题:发送者或接收者对象已被销毁。确保连接时对象已构造,且在连接有效期内不被销毁。
- 信号或槽签名不匹配:参数类型、数量或 const 属性必须兼容。
- 忘记 Q_OBJECT 宏:自定义的类如果包含信号或槽,必须在类定义的私有部分开头添加
Q_OBJECT宏。 - 线程问题:默认情况下,信号槽连接是直连(
Qt::DirectConnection),在跨线程时需要使用队列连接(Qt::QueuedConnection)。
4.2 Qt 的内存管理:父子对象机制
Qt 引入了一套基于对象树的所有权模型来简化内存管理。当一个QObject派生类对象被创建时,可以指定一个父对象(parent)。当父对象被销毁时,它会自动销毁其所有的子对象。
QPushButton *button = new QPushButton(“Click me”, this); // `this`(MainWindow) 是 button 的父对象在这个例子中,button的父对象是MainWindow。当MainWindow被销毁时(例如窗口关闭),它会自动删除button,你不需要手动delete button。
重要规则:
- 所有继承自
QObject的类(包括所有 Widgets)都适用此规则。 - 在堆上创建(
new)且有父对象的对象,不要手动delete。 - 在堆上创建但无父对象的对象,需要手动管理其生命周期。
- 在栈上创建的对象(局部变量)会随作用域结束自动析构,通常也不设父对象。
滥用此机制或理解错误会导致双重删除(crash)或内存泄漏。
4.3 .ui 文件与 uic 工具
.ui文件是 XML 格式的界面描述文件。在构建时,uic(User Interface Compiler)工具会将其转换为对应的ui_*.h头文件。这个头文件中定义了一个类(如Ui::MainWindow),包含了界面所有部件的指针(如QPushButton *btnTest)。
在MainWindow的构造函数中,ui->setupUi(this)做了以下几件事:
- 创建
Ui::MainWindow类中描述的所有界面部件。 - 将这些部件设置到
this(主窗口)的布局中。 - 将界面部件的指针赋值给
ui对象的成员变量(如ui->btnTest),以便我们在代码中访问。
因此,不要在构造函数ui->setupUi(this)调用之前,访问ui->xxx,因为那时这些指针还是空的。
5. 开发中常见问题与深度排查
即使按照教程操作,在实际开发中仍会遇到各种问题。以下是一些最常见问题的排查思路和解决方案。
5.1 程序编译成功但运行时崩溃或无法启动
这是最令人头疼的问题之一。错误信息可能很模糊,如“程序异常结束”。
排查步骤:
- 检查依赖库:这是最常见的原因。在 Windows 上,使用
windeployqt工具可以自动收集可执行文件所需的所有 Qt 动态库。
运行后,该目录下会包含所有必要的 DLL。再次运行# 在 Qt 命令行环境中,进入你的 .exe 所在目录 windeployqt --release MyApp.exeMyApp.exe测试。如果问题解决,说明是部署环境缺失 Qt 库。 - 检查插件路径:如果错误信息明确提到 “no Qt platform plugin could be initialized”,说明程序找到了 Qt 核心库,但没找到平台插件(如
windows,cocoa等)。平台插件位于plugins/platforms目录下。确保这个目录在应用程序的搜索路径下。使用windeployqt会自动处理这个问题。 - 调试模式运行:在 Qt Creator 中以调试模式运行程序。当程序崩溃时,调试器会停在出错的位置。查看调用堆栈(Call Stack),找到你自己代码的文件和行号,这是问题的根源。
- 检查野指针和内存越界:在 C++ 中,访问已释放的内存或数组越界会导致不可预知的行为。使用 Qt 的父子对象机制可以减少手动内存管理的错误。同时,可以使用工具如
AddressSanitizer(GCC/Clang)或 Visual Studio 的调试器内存检查功能来辅助定位。
5.2 Qt Creator 调试输出中文乱码
在 Qt Creator 的“应用程序输出”或“调试输出”面板中,中文字符可能显示为乱码。这是因为源代码文件的编码、编译器执行编码和终端显示编码不一致。
解决方案:
- 统一源代码文件编码:在 Qt Creator 中,点击
工具->选项->文本编辑器->行为,将“默认编码”设置为UTF-8,并勾选“如果编码是 UTF-8 则添加 BOM”。然后转换现有文件编码。 - 设置编译器执行字符集(MSVC):对于 MSVC 编译器,需要在项目文件(
.pro)或 CMakeLists.txt 中指定。在.pro文件中添加:# 使用 UTF-8 编码 win32:msvc { QMAKE_CXXFLAGS += /utf-8 QMAKE_CFLAGS += /utf-8 } - 设置控制台代码页(Windows):Windows 控制台默认代码页是 GBK。可以在程序启动时强制设置为 UTF-8,但这可能影响其他部分。一个更简单的方法是在输出日志到文件或界面时,确保使用正确的编码转换。对于输出到 Qt Creator 内部面板,通常完成步骤1和2即可解决。
5.3 发布程序时文件过大
使用 MSVC 编译的 Release 版本,如果直接静态链接 C++ 运行时库,并打包所有 Qt 模块,程序体积会很大。
优化建议:
- 动态链接:这是默认方式。发布时带上必要的 DLL,而不是将 Qt 库静态编译进程序。
- 使用
windeployqt精确打包:windeployqt会分析你的可执行文件,只复制它实际链接的 Qt 模块 DLL,而不是全部。 - 编译器优化:确保在 Release 配置下编译,并开启优化选项(如
/O2或-O2)。 - 移除未使用的模块:在
.pro文件中,只QT +=你真正用到的模块,如core gui widgets,不要添加network,sql等未使用的模块。 - 考虑静态编译(高级):将 Qt 静态编译到程序中,可以生成单个可执行文件,但过程复杂,且需遵守 Qt 的 LGPL 许可条款(提供你的目标代码)。静态编译后的文件体积可能更大,但依赖更少。
5.4 界面布局在调整窗口大小时行为异常
Qt 提供了强大的布局管理器(Layouts)来自动排列部件。常见问题有部件不拉伸、留白过多或重叠。
排查与解决:
- 正确设置布局:在 Qt Designer 中,选中需要布局的部件和容器,然后点击布局按钮(水平、垂直、网格等)。确保顶级窗口本身也设置了布局。
- 设置大小策略:每个部件都有水平大小策略(
QSizePolicy::HorizontalPolicy)和垂直大小策略。例如,一个按钮的默认策略是Fixed(固定大小),而文本框的默认策略是Expanding(可扩展)。在 Designer 的属性编辑器或代码中调整sizePolicy属性。 - 设置拉伸因子:在布局中,可以使用
setStretchFactor或在 Designer 中设置layoutStretch属性来分配不同部件在布局中的拉伸比例。 - 最小和最大尺寸:检查部件是否设置了不合理的
minimumSize或maximumSize,这可能会限制布局管理器的调整。
5.5 信号槽连接无效(无响应)
点击按钮没反应,定时器不触发,都是信号槽连接失败的典型表现。
系统化排查清单:
- 检查连接语法:确认
connect语句书写正确,信号和槽的签名匹配。使用新式语法(函数指针)编译器能在编译期检查出更多错误。 - 检查对象是否存活:在连接建立后,发送者或接收者对象是否被意外销毁?在槽函数中打印日志或使用调试器确认。
- 检查线程:如果发送者和接收者处于不同线程,默认的直连(
Qt::DirectConnection)是危险的。需要使用Qt::QueuedConnection。connect(obj1, &Class1::signal, obj2, &Class2::slot, Qt::QueuedConnection); - 检查事件循环:信号槽机制依赖于事件循环(
QApplication::exec())。如果你在一个长时间运行的函数中发射信号,但在该函数结束前没有返回事件循环,那么连接的槽函数就不会被调用。对于耗时操作,应使用多线程(QThread)或异步任务。 - 使用调试输出:在信号发射处和槽函数入口处添加
qDebug()输出,看信号是否发射,槽是否被调用。 - 验证连接结果:
connect函数返回一个QMetaObject::Connection对象,可以判断连接是否成功(虽然不常用)。if(!connect(...)) { qDebug() << “连接失败!”; }
6. 从学习到生产:最佳实践与扩展方向
掌握基础并能够排错后,要写出易于维护、健壮的 Qt 应用程序,还需要遵循一些最佳实践。
6.1 项目组织与代码规范
- 分离界面与逻辑:不要将所有代码都写在
MainWindow里。将业务逻辑、数据模型独立成单独的类。MainWindow应主要处理界面交互。 - 使用模型/视图架构:对于列表、表格、树形等数据展示,优先使用 Qt 的 Model/View 框架(如
QListView,QTableView,QStandardItemModel),而不是直接操作 Widget。这有利于数据与显示的分离。 - 资源文件:将图片、图标、翻译文件等放入 Qt 资源系统(
.qrc文件),编译进程序,避免外部文件依赖。 - 国际化:使用
tr()包裹所有用户可见的字符串,方便后续使用Qt Linguist工具进行翻译。 - 日志系统:不要仅依赖
qDebug(),在生产环境中集成一个更强大的日志库(如 spdlog),支持日志级别、文件输出和日志轮转。
6.2 性能与内存优化
- 避免在频繁调用的槽函数中进行耗时操作:这会阻塞 GUI 线程,导致界面卡顿。将耗时操作移至工作线程(
QThread,QtConcurrent)。 - 合理使用
update()和repaint():需要重绘界面时,调用update(),它会安排一个重绘事件,由事件循环统一处理,避免短时间内多次重绘。repaint()是立即重绘,慎用。 - 管理大型数据集合:对于
QList,QVector等容器,如果预先知道大小,使用reserve()预留空间,可以减少多次重新分配的开销。 - 使用隐式共享:Qt 的许多类(如
QString,QImage,QByteArray)使用隐式共享(写时复制),在值传递时开销很小。但也要注意,修改一个共享副本时,如果其引用计数大于1,会发生深拷贝。
6.3 下一步学习路径
在掌握了 Widgets 编程基础后,可以根据兴趣和项目需求选择深入的方向:
- QML 与 Qt Quick:用于开发现代、炫酷的触摸式 UI,尤其在移动端和嵌入式设备上。它与传统的 Widgets 是不同的技术路径。
- 网络编程:学习
QNetworkAccessManager,QTcpSocket,QUdpSocket进行 HTTP 请求和自定义协议通信。 - 数据库:使用
QSqlDatabase,QSqlQuery连接和操作 SQL 数据库。 - 多线程:深入理解
QThread,QThreadPool,QtConcurrent,以及线程间通信(信号槽、事件、共享内存)。 - 图形视图框架:对于需要自定义绘图、处理大量图元(如流程图、地图)的应用,学习
QGraphicsView,QGraphicsScene,QGraphicsItem。 - 插件系统:学习如何开发 Qt 插件,实现应用程序的模块化扩展。
Qt 是一个庞大的生态系统,循序渐进,由需求驱动学习,是掌握它的最好方式。从解决一个具体的小问题开始,逐步构建起自己的知识体系。
