C++与Qt5实战:从零构建桌面待办事项应用

📅 2026/7/24 5:14:23 👁️ 阅读次数 📝 编程学习
C++与Qt5实战:从零构建桌面待办事项应用

1. 项目概述与核心价值

最近在整理硬盘,翻到了一个几年前自己边学边做的《C++ 与 Qt5 GUI 编程实战》开源项目教程。这个项目最初源于我自己的学习困境:当时想从纯后端C++转向带界面的桌面应用开发,市面上资料要么是纯理论,要么是零散的“Hello World”示例,很难串联成一个完整的、能上手的项目。于是,我决定自己动手,用做一个真实可用的“个人待办事项管理工具”作为主线,把C++、Qt5的核心知识点像串珍珠一样串起来,并全程开源。没想到,这个项目在GitHub上获得了不少关注,很多初学者反馈说,这种“以战代练”的方式让他们真正理解了如何用C++和Qt5构建一个现代化的GUI应用。

这个教程项目,本质上是一个从零到一的完整开发指南。它不满足于教你弹出一个窗口、放几个按钮,而是带你经历一个真实桌面应用开发的全生命周期:从项目创建、界面设计、业务逻辑实现,到数据持久化、打包发布,乃至一些进阶的调试和优化技巧。它的核心价值在于实战性系统性。对于有C++基础但没接触过GUI,或者用过其他GUI框架想转战Qt的开发者来说,这个项目提供了一个绝佳的“脚手架”。你不仅可以照着做,更能理解每一步背后的设计考量和最佳实践,最终获得独立开发类似应用的能力。项目里用到的技术栈非常经典且不过时:C++11/14作为核心语言,Qt5作为GUI框架,SQLite作为本地数据库,CMake进行项目构建。这些都是工业界开发桌面应用,尤其是对性能和原生体验有要求的应用时,经久不衰的选择。

2. 项目整体架构与设计思路

2.1 为什么选择“待办事项”作为实战项目?

在构思教程载体时,我考虑过很多点子,比如计算器、文本编辑器、简易绘图板等。最终选择“待办事项管理工具”,主要基于以下几点考量:

  1. 复杂度适中,覆盖知识点全面:一个完整的待办事项应用,需要前端界面(列表、输入框、按钮、菜单)、后端业务逻辑(增删改查、状态切换)、数据持久化(本地存储)。它比计算器复杂,能引入更多Qt控件和设计模式;又比一个完整的办公软件简单,确保教程焦点集中。
  2. 贴近实际需求,有实用价值:做出来的东西自己真的能用,这是持续学习的强大动力。一个功能完善的待办工具,本身就是生产力工具。
  3. 易于扩展和想象:完成基础功能后,学员可以很容易地为其添加新功能,如分类标签、优先级设置、到期提醒、数据统计图表等,这为自主学习提供了无限空间。

2.2 技术选型背后的逻辑

  • C++11/14:这是现代C++开发的一个“甜蜜点”。auto关键字、范围for循环、智能指针(std::shared_ptr,std::unique_ptr)、Lambda表达式等特性,能极大提升开发效率和代码安全性,同时又不至于像C++17/20那样在某些环境存在兼容性问题。教程中会刻意展示如何用现代C++特性写出更简洁、更安全的Qt代码。
  • Qt5:选择Qt5而非Qt6,主要是出于稳定性和生态成熟度的考虑。Qt5 LTS版本(如5.15)拥有极其庞大的用户群和丰富的第三方资源,网络上几乎你遇到的任何问题都能找到解决方案。对于初学者,避开新版本可能存在的微小兼容性陷阱,能更平滑地入门。教程重点使用的模块包括:
    • Qt Widgets:用于构建传统的桌面窗口应用,是学习Qt GUI编程的基石。
    • Qt Core:信号与槽、容器类、文件IO、多线程等核心非GUI功能。
    • Qt SQL:用于连接和操作SQLite数据库。
  • SQLite:作为单机桌面应用的数据存储方案,SQLite几乎是唯一选择。它无需安装数据库服务器,一个文件就是整个数据库,完美契合“个人待办事项”这种轻量级、本地化的场景。通过Qt SQL模块操作它,也能学习到数据库编程的基本方法。
  • CMake:现代C++项目的标准构建工具。相比于Qt自带的.pro文件(qmake),CMake更通用、更强大,也更容易与CI/CD、跨平台编译等现代开发流程集成。教程会从零开始编写CMakeLists.txt,让你理解如何组织一个Qt项目。

2.3 应用架构设计

整个应用采用经典的Model-View架构,这是Qt框架的核心设计模式之一,非常适合数据展示类应用。

  1. Model(模型):负责管理数据。我们创建一个TodoModel类,它内部封装了对SQLite数据库的所有操作(增、删、改、查)。同时,为了让这个模型能直接与Qt的视图组件(如QListViewQTableView)绑定,我们会让它继承自QAbstractTableModel。这样,当模型中的数据发生变化时,视图会自动更新。
  2. View(视图):负责展示数据。主界面使用QMainWindow,包含菜单栏、工具栏、状态栏和一个中心部件。中心部件采用QWidget配合布局管理器(如QVBoxLayout,QHBoxLayout)来组织各个控件:一个用于显示待办列表的QTableView,一个用于输入新任务的QLineEdit,以及“添加”、“删除”、“标记完成”等QPushButton
  3. Controller(控制器):在Qt的MV模式中,控制器角色通常由“信号与槽”机制和主窗口的业务逻辑代码共同承担。例如,当用户点击“添加”按钮(发出clicked()信号),对应的槽函数会从输入框获取文本,然后调用TodoModel的接口将数据插入数据库,模型数据更新后,表格视图自动刷新。

这种架构的优势是清晰地将数据、界面和逻辑解耦。修改界面样式不影响数据层,更换数据库(比如未来想支持网络同步)也只需修改模型内部实现,界面和业务逻辑几乎不用动。

注意:很多初学者喜欢把所有代码都写在主窗口类里,导致后期难以维护。本教程从一开始就强制进行模块化设计,虽然前期稍显繁琐,但对培养良好的工程习惯至关重要。

3. 开发环境搭建与项目初始化

3.1 工具链选择与安装

工欲善其事,必先利其器。一个顺手的开发环境能事半功倍。

  1. Qt 安装

    • 推荐方式:从Qt官网下载在线安装器(Qt Maintenance Tool)。不建议下载整个离线安装包,体积太大。
    • 组件选择:在安装时,务必勾选以下组件:
      • Qt 5.15.2(或最新的LTS版本) 下的MSVC 2019 64-bit(如果你用Visual Studio)或MinGW 8.1.0 64-bit(如果你用MinGW)。
      • Qt Creator:这是Qt官方IDE,对Qt开发的支持最完善,特别是其集成的UI设计器(Qt Designer)和调试工具。
      • CMake:如果系统没有,可以在这里一并安装。
    • 关于 Qt WebKit:在搜索热词中看到“qt5如何安装webkit”。需要明确,Qt WebKit模块在Qt5.6之后已被标记为废弃,并在后续版本中移除。Qt推荐使用新的Qt WebEngine模块(基于Chromium)来替代。如果你的项目必须使用WebKit,可能需要寻找非常老的Qt版本或第三方移植,但这会带来巨大的安全和兼容性风险。对于新项目,强烈建议使用Qt WebEngine或避免内嵌浏览器需求。
  2. IDE/编辑器

    • Qt Creator:开箱即用,与Qt框架无缝集成,是学习和开发Qt应用的首选。其内置的UI设计器可以拖拽生成界面代码,非常适合初学者理解控件和布局。
    • Visual Studio:如果你更熟悉VS生态,可以安装“使用C++的桌面开发”工作负载,并在安装Qt时选择MSVC套件。之后需要安装“Qt VS Tools”扩展,以便在VS中管理Qt项目。
    • VSCode:轻量灵活,通过安装C++扩展、CMake Tools扩展和Qt相关的插件(如qt-vscode),也能获得很好的开发体验。适合喜欢高度自定义的开发者。
  3. 编译器:根据你选择的Qt套件,对应使用MSVC或MinGW。确保系统环境变量配置正确。

3.2 创建第一个CMake Qt项目

我们不用Qt Creator的向导,而是手动创建,以彻底理解项目结构。

  1. 创建项目目录:例如TodoApp

  2. 编写 CMakeLists.txt:在TodoApp根目录下创建CMakeLists.txt,这是项目的总蓝图。

    cmake_minimum_required(VERSION 3.16) project(TodoApp VERSION 1.0.0 LANGUAGES CXX) # 设置C++标准 set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 自动处理Qt的MOC、UIC、RCC set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) # 查找所需的Qt组件 find_package(Qt5 REQUIRED COMPONENTS Core Widgets Sql) # 添加可执行文件目标 add_executable(TodoApp src/main.cpp src/mainwindow.cpp src/mainwindow.h src/todomodel.cpp src/todomodel.h resources/resources.qrc ) # 链接Qt库到目标 target_link_libraries(TodoApp Qt5::Core Qt5::Widgets Qt5::Sql) # 设置可执行文件的输出目录(可选) set_target_properties(TodoApp PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )

    这段CMake脚本做了几件关键事:指定C++11标准;启用Qt的元对象编译器(MOC)等自动化工具;查找并链接Qt Core, Widgets, Sql三个模块;定义了最终生成的可执行文件TodoApp及其源文件。

  3. 创建基础源文件

    • src/main.cpp:程序入口,创建并显示主窗口。
    #include <QApplication> #include "mainwindow.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); // 每个Qt Widgets应用都需要一个QApplication对象 MainWindow window; window.show(); // 显示窗口 return app.exec(); // 进入主事件循环 }
    • src/mainwindow.h/src/mainwindow.cpp:主窗口类的声明和定义(暂时留空或写个简单构造函数)。
    • src/todomodel.h/src/todomodel.cpp:数据模型类(暂时留空)。
    • resources/resources.qrc:Qt资源文件,用于将图标、翻译文件等打包进可执行程序。
  4. 构建与运行

    # 在项目根目录下 mkdir build && cd build cmake .. -G "MinGW Makefiles" # 如果你用MinGW,指定生成器。Windows下用MSVC可省略-G参数。 cmake --build . # 运行生成的可执行文件,通常在 ./bin 或 ./Debug/Release 目录下

实操心得:第一次手动配置CMake可能会遇到各种问题,比如找不到Qt、链接错误等。关键检查点:1)find_package是否成功;2) 环境变量PATH是否包含Qt的bin目录和编译器的bin目录;3) 生成器(-G)是否与你的编译器匹配。耐心解决第一次,以后就是复制粘贴了。

4. 核心模块实现详解

4.1 数据模型 (TodoModel) 的实现

模型是应用的心脏,它直接与数据库交互,并为视图提供数据。

  1. 数据库初始化: 在TodoModel的构造函数中,我们需要建立与SQLite数据库的连接,并创建必要的表。

    // todomodel.cpp #include <QSqlDatabase> #include <QSqlError> #include <QSqlQuery> #include <QStandardPaths> #include <QDir> TodoModel::TodoModel(QObject *parent) : QAbstractTableModel(parent) { // 确定数据库文件路径,通常放在用户数据目录 QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); QDir dir(dataDir); if (!dir.exists()) { dir.mkpath(dataDir); } QString dbPath = dataDir + "/todos.db"; // 打开或创建数据库 QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName(dbPath); if (!db.open()) { qCritical() << "Cannot open database:" << db.lastError(); return; } // 创建表(如果不存在) QSqlQuery query; QString createTableSql = R"( CREATE TABLE IF NOT EXISTS todos ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, description TEXT, is_done BOOLEAN NOT NULL DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) )"; if (!query.exec(createTableSql)) { qCritical() << "Create table failed:" << query.lastError(); } // 可以在这里触发一个信号,通知界面模型已就绪,或者直接调用一个加载数据的方法 loadTodos(); }

    QStandardPaths用于获取跨平台的标准路径,AppDataLocation在Windows上是AppData/Local,在macOS上是Library/Application Support,在Linux上是.local/share

  2. 实现 QAbstractTableModel 的虚函数: 要让模型能在QTableView中工作,必须实现以下几个核心虚函数:

    // todomodel.h class TodoModel : public QAbstractTableModel { Q_OBJECT public: // ... 构造函数等其他成员 int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; Qt::ItemFlags flags(const QModelIndex &index) const override; private: struct TodoItem { int id; QString title; QString description; bool isDone; QDateTime createdAt; QDateTime updatedAt; }; QVector<TodoItem> m_todos; // 内存中缓存所有待办项 void loadTodos(); // 从数据库加载数据到m_todos };
    • rowCount/columnCount:告诉视图有多少行/列数据。我们可能设计为3列:完成状态、标题、创建时间。
    • data:这是最重要的函数,根据index(行、列)和role(角色,如显示文本、字体颜色、背景色等)返回对应的数据。例如,当role == Qt::DisplayRolecolumn == 1时,返回m_todos[row].title
    • headerData:提供表头信息。
    • setData:当用户在视图上编辑单元格(如勾选完成状态)时,此函数被调用,用于更新模型内部数据(m_todos)和底层数据库。
    • flags:返回每一项的标志,例如Qt::ItemIsEditable表示该项可编辑。
  3. 实现增删改查方法: 在TodoModel中提供公共接口,供控制器(主窗口)调用。

    bool TodoModel::addTodo(const QString &title, const QString &desc) { // 插入数据库 QSqlQuery query; query.prepare("INSERT INTO todos (title, description) VALUES (?, ?)"); query.addBindValue(title); query.addBindValue(desc); if (!query.exec()) { qWarning() << "Insert failed:" << query.lastError(); return false; } // 获取新插入的ID int newId = query.lastInsertId().toInt(); // 更新内存缓存 beginInsertRows(QModelIndex(), m_todos.size(), m_todos.size()); // 通知视图即将插入行 m_todos.append({newId, title, desc, false, QDateTime::currentDateTime(), QDateTime::currentDateTime()}); endInsertRows(); // 通知视图插入完成 return true; } bool TodoModel::removeTodo(int row) { if (row < 0 || row >= m_todos.size()) return false; int id = m_todos.at(row).id; QSqlQuery query; query.prepare("DELETE FROM todos WHERE id = ?"); query.addBindValue(id); if (!query.exec()) { qWarning() << "Delete failed:" << query.lastError(); return false; } beginRemoveRows(QModelIndex(), row, row); // 通知视图即将移除行 m_todos.removeAt(row); endRemoveRows(); return true; }

    关键点:任何修改m_todos(作为模型内部数据)的操作,都必须包裹在beginInsertRows/endInsertRowsbeginRemoveRows/endRemoveRowsbeginResetModel/endResetModel等通知函数中。这是Qt模型/视图框架的强制要求,只有这样,视图才能知道数据发生了变化并自动更新UI。

4.2 用户界面 (MainWindow) 的设计与实现

界面是用户直接交互的部分,良好的设计能提升用户体验。

  1. 使用 Qt Designer 设计界面

    • 在Qt Creator中,可以右键项目->添加新文件->Qt->Qt Designer Form Class,选择MainWindow模板,创建mainwindow.ui文件。
    • 在Designer中拖拽控件:一个QTableView,一个QLineEdit,几个QPushButton,可能还有一个QTextEdit用于输入描述。
    • 使用布局管理器(Layouts)来排列控件,确保窗口缩放时界面不会混乱。例如,将输入框和按钮放在一个水平布局(QHBoxLayout)中,再将这个水平布局和表格视图放在一个垂直布局(QVBoxLayout)里,最后将这个垂直布局设置为中心部件的布局。
    • 为重要的控件设置一个清晰的objectName,如tableView,titleLineEdit,addButton,以便在代码中引用。
  2. 在代码中关联界面与模型

    • Qt Creator会自动生成ui_mainwindow.h文件,其中包含一个Ui::MainWindow类,它定义了界面上的所有控件指针。
    • MainWindow的构造函数中,我们需要设置UI,并将模型与视图关联。
    // mainwindow.cpp #include "ui_mainwindow.h" #include "todomodel.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , m_model(new TodoModel(this)) // 创建数据模型 { ui->setupUi(this); // 初始化UI,这是关键一步 // 将模型设置给表格视图 ui->tableView->setModel(m_model); // 可以设置表格的列宽、选择行为等 ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableView->horizontalHeader()->setStretchLastSection(true); // 连接信号与槽 connect(ui->addButton, &QPushButton::clicked, this, &MainWindow::onAddButtonClicked); connect(ui->deleteButton, &QPushButton::clicked, this, &MainWindow::onDeleteButtonClicked); connect(ui->tableView, &QTableView::doubleClicked, this, &MainWindow::onTodoDoubleClicked); }
  3. 实现业务逻辑槽函数

    void MainWindow::onAddButtonClicked() { QString title = ui->titleLineEdit->text().trimmed(); if (title.isEmpty()) { QMessageBox::warning(this, tr("Warning"), tr("Title cannot be empty!")); return; } QString desc = ui->descTextEdit->toPlainText(); if (m_model->addTodo(title, desc)) { ui->titleLineEdit->clear(); ui->descTextEdit->clear(); ui->titleLineEdit->setFocus(); // 清空输入框并聚焦,方便连续输入 } else { QMessageBox::critical(this, tr("Error"), tr("Failed to add new todo.")); } } void MainWindow::onDeleteButtonClicked() { QModelIndexList selected = ui->tableView->selectionModel()->selectedRows(); if (selected.isEmpty()) { QMessageBox::information(this, tr("Info"), tr("Please select a row to delete.")); return; } // 从后往前删除,避免索引变化导致的问题 for (int i = selected.count() - 1; i >= 0; --i) { int row = selected.at(i).row(); m_model->removeTodo(row); } }

4.3 数据持久化与高级特性

  1. 数据库事务:对于批量删除或修改操作,使用事务可以保证数据一致性并提升性能。

    bool TodoModel::removeTodos(const QVector<int>& rows) { QSqlDatabase db = QSqlDatabase::database(); // 获取当前数据库连接 if (!db.transaction()) { // 开始事务 qWarning() << "Start transaction failed"; return false; } bool allSuccess = true; // ... 循环执行删除操作 if (allSuccess) { if (!db.commit()) { // 提交事务 qWarning() << "Commit transaction failed"; allSuccess = false; } } else { db.rollback(); // 回滚事务 } return allSuccess; }
  2. 自定义委托 (Delegate):如果你想让“完成状态”这一列显示为复选框,而不是文本“true/false”,就需要为这一列设置一个QStyledItemDelegate的子类,重写它的painteditorEvent方法。这属于Qt模型/视图框架的进阶内容,教程中会详细演示如何实现一个简单的复选框委托。

  3. 样式表 (QSS):Qt支持使用类似CSS的样式表来美化界面。你可以为整个应用或单个控件设置样式。

    // 在主窗口构造函数中 this->setStyleSheet("QMainWindow { background-color: #f0f0f0; }" "QTableView { alternate-background-color: #e8e8e8; }" "QPushButton { background-color: #4CAF50; color: white; border-radius: 4px; padding: 5px; }" "QPushButton:hover { background-color: #45a049; }");

5. 项目构建、调试与发布

5.1 使用CMake进行高效构建

我们已经在CMakeLists.txt中配置了基础构建。随着项目变大,你可能需要:

  • 添加子目录:将模型、视图、工具类等分到不同的CMakeLists.txt中,使用add_subdirectory引入。
  • 管理资源文件:确保resources.qrc被正确包含,并使用qt5_add_resources命令(如果使用CMake 3.16+且find_package了Qt5,CMAKE_AUTORCC已自动处理)。
  • 处理翻译文件 (.ts):使用qt5_add_translation命令来生成和发布多语言支持。

5.2 调试技巧与常见问题排查

  1. 使用 qDebug() 和 qCritical():这是Qt中最简单的日志输出方式,在调试时非常有用。记得在发布版本中可以通过定义QT_NO_DEBUG_OUTPUT来关闭它们。
  2. 善用 Qt Creator 的调试器:可以直观地查看Qt特有的对象,如QString的内容、QList的元素等。
  3. 内存管理:虽然使用了现代C++智能指针,但Qt有自己的父子对象内存管理机制。将QObject派生类的子对象指定父对象(通常在构造函数中传入this),当父对象销毁时,会自动销毁所有子对象。注意:不要混合使用智能指针和Qt的父子机制管理同一个对象,这会导致双重释放。
  4. 信号与槽连接失败:这是最常见的问题之一。检查点:
    • 发送者和接收者是否都是QObject的派生类(或其子类)。
    • 槽函数的签名是否与信号匹配(参数类型、数量、const修饰符)。
    • 在C++11及以上,推荐使用新式语法connect(sender, &Sender::signal, receiver, &Receiver::slot),它能在编译时检查类型安全。
    • 如果使用QML,连接方式不同,但本教程不涉及QML。

5.3 打包发布可执行文件

开发完成后,你需要将应用分发给没有开发环境的用户。Qt应用发布需要携带相关的运行时库(DLL)。

  1. 找到依赖的DLL

    • Windows (MinGW):在Qt安装目录的bin文件夹下(如C:\Qt\5.15.2\mingw81_64\bin),找到Qt5Core.dll,Qt5Widgets.dll,Qt5Gui.dll,Qt5Sql.dll等,以及libgcc_s_seh-1.dll,libstdc++-6.dll,libwinpthread-1.dll等编译器运行时库。
    • Windows (MSVC):同样在Qt的bin目录下找对应的DLL,此外还需要VC++ Redistributable运行时库(msvcp140.dll,vcruntime140.dll等),用户可能需要单独安装或你一并打包。
  2. 使用 windeployqt 工具 (Windows):这是Qt官方提供的部署工具,能自动扫描你的exe文件,找出所有需要的Qt库,并复制到目标文件夹。

    # 在构建目录下,假设你的exe在 ./bin/TodoApp.exe cd /path/to/your/build/bin windeployqt TodoApp.exe

    执行后,当前目录下会多出许多Qt的DLL和必要的文件夹(如platforms)。

  3. 创建发布包:将TodoApp.exewindeployqt复制过来的所有文件、你自己的数据库文件(或让程序在首次运行时创建)以及可能需要的其他资源(如图标、配置文件)一起打包。可以使用Inno SetupNSIS等工具制作安装程序。

  4. macOS 和 Linux:过程类似,macOS使用macdeployqt,Linux通常需要指定库的安装路径或使用AppImage等打包格式。

避坑指南:发布后最常见的错误是“无法找到Qt平台插件”或程序启动后崩溃。99%的原因都是必要的DLL或插件文件夹(特别是platforms文件夹下的qwindows.dll)没有正确打包。务必确保发布目录的结构与开发环境中运行时的结构一致。

6. 从Qt5到未来:进阶学习路径

完成这个基础项目后,你已经掌握了使用C++和Qt5开发桌面应用的核心技能。但Qt的世界远不止于此。你可以基于这个项目,尝试以下方向进行深化和扩展:

  1. 界面美化与自定义控件:深入学习QSS,制作更精美的界面。继承QWidget或现有控件,绘制完全自定义的控件(重写paintEvent)。
  2. 多线程与异步:如果待办事项需要处理网络请求(如同步到云端)或耗时计算,必须使用多线程,避免阻塞UI主线程导致界面卡顿。学习QThreadQtConcurrent以及信号槽的跨线程连接类型(Qt::ConnectionType)。
  3. 插件化架构:设想你的待办事项工具可以支持不同的存储后端(本地SQLite、网络API)。可以设计一个插件接口,通过动态库(DLL/dylib/so)的方式加载不同的存储插件。
  4. 探索 Qt Quick / QML:对于需要更炫酷、更动态界面的应用,Qt Quick(QML)是更好的选择。它是一种声明式语言,类似于JSON,专门用于构建流畅的现代UI。你可以考虑用QML重写前端,而C++作为后端逻辑。
  5. 跨平台移动端:Qt不仅支持桌面(Windows, macOS, Linux),也支持移动平台(iOS, Android)。虽然移动端开发更推荐使用Qt Quick,但了解如何为移动设备调整UI布局和交互逻辑是很有价值的技能。
  6. 现代化C++特性融合:在模型类中尝试使用std::optionalstd::variant,使用更安全的容器算法,探索将部分逻辑用std::function和Lambda进行重构,让代码更符合现代C++风格。

这个《C++ 与 Qt5 GUI 编程实战》项目,就像一把钥匙,为你打开了桌面应用开发的大门。它提供的不是一堆零散的知识点,而是一个完整的、可运行的、可扩展的代码骨架。我始终认为,编程最好的学习方式就是动手去做一个东西,在解决一个个具体问题的过程中,那些抽象的概念和API才会变得鲜活起来。希望你在跟随这个教程实践时,不仅能复现出一个待办事项工具,更能真正理解其背后的设计思想,并最终有能力创造出属于自己的、更复杂的桌面应用。