Qt在CAE开发中的角色与核心机制总览 / The Role and Core Mechanisms of Qt in CAE Development
📅 创建时间:2026-07-13 🏷️ 标签:#Qt #C++ #CAE #工业软件 #入门总览 #MOC 📚 前置知识:Technical Stack,Cpp Project Fundamentals
📋 本章目标
- 理解 Qt 在工业 CAE 软件中的优势、适用边界及与其他 GUI 技术的取舍
- 掌握Qt版本演进路线(Qt5 → Qt6)及迁移要点
- 理解Qt模块化架构——Core、Widgets、OpenGL、Concurrent的分工
- 理解Qt与标准C++的关系——MOC做了什么、为什么需要代码生成
- 掌握qmake与CMake+Qt两种构建体系的差异
- 建立CAE开发中Qt使用的全景心智模型
- 能够独立搭建一个Qt6+CMake的CAE骨架项目
专题扩展
第1部分:为什么CAE软件选Qt?
1.1 工业软件的GUI十字路口
在CAE软件开发中,GUI框架的选择不是在"好与坏"之间选,而是在"不同代价"之间权衡:
┌─────────────────────────────────────────────────────────────┐
│ CAE开发GUI框架选型对比 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 框架 优势 在CAE开发中的致命问题 │
│ ──────── ────────────────────── ────────────────────── │
│ MFC • Windows原生快 • 仅Windows,CAE需跨平台 │
│ • 历史代码多 • 现代C++支持差 │
│ • COM集成好 • 无信号槽,回调地狱 │
│ │
│ WPF • 现代UI美观 • 仅Windows │
│ • XAML声明式 • C#生态,与C++求解器割裂 │
│ • 数据绑定 • 托管/非托管边界开销 │
│ │
│ Electron • Web技术栈 • 内存占用巨大(>500MB) │
│ • 前端人才多 • 无法直接调用C++求解器 │
│ • 跨平台 • 不适合实时3D渲染 │
│ │
│ Qt • 真正跨平台 • 学习曲线陡峭 │
│ • C++原生,易集成求解器 • 依赖代码生成与工具链 │
│ • 信号槽,松耦合 • 商业许可证费用 │
│ • OpenGL/VTK深度集成 • Qt6 不再支持Qt5部分API │
│ │
└─────────────────────────────────────────────────────────────┘CAE开发的特殊需求决定了Qt是事实标准:
┌─────────────────────────────────────────────────────────────┐
│ CAE软件开发的核心挑战 → Qt的对策 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 挑战1:求解器是C/C++写的(Eigen, PETSc, MKL) │
│ → Qt = C++原生框架,直接调用无FFI/序列化开销 │
│ │
│ 挑战2:需要实时3D渲染(网格预览、结果云图) │
│ → Qt + QOpenGLWidget/VTK 无缝集成 │
│ │
│ 挑战3:Win/Linux双平台 │
│ → Qt 一套代码,多平台编译运行 │
│ │
│ 挑战4:UI与求解器异步(不阻塞界面) │
│ → 信号槽 + QueuedConnection 天然跨线程通信 │
│ │
│ 挑战5:插件系统(导入/导出/求解器/后处理) │
│ → QPluginLoader负责发现;ABI仍需版本和工具链约束 │
│ │
│ 挑战6:国际化(中/英/日/德多语言) │
│ → QTranslator + Qt Linguist 一整套i18n方案 │
│ │
└─────────────────────────────────────────────────────────────┘1.2 哪些CAE软件在用Qt
┌─────────────────────────────────────────────────────────────┐
│ Qt驱动的CAE/工业软件 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 软件 用途 Qt使用方式 │
│ ────────────────────── ──────────────── ─────────────── │
│ ANSYS Discovery 实时仿真+拓扑优化 全套Qt Widgets │
│ ParaView 大规模科学可视化 Qt + VTK深度集成│
│ FreeCAD 参数化3D CAD Qt + Python绑定 │
│ Gmsh 网格生成器 Qt + OpenGL │
│ OpenFOAM GUI Wrapper CFD前后处理 Qt封装命令行工具 │
│ CalculiX GraphiX FEA前后处理 Qt + OpenGL │
│ Salome 数值模拟平台 Qt + VTK+OCC │
│ Dassault 3DEXPERIENCE 全生命周期平台 Qt (部分模块) │
│ │
│ 共同特征:都用 Qt + C++ 做核心架构 │
│ │
└─────────────────────────────────────────────────────────────┘第2部分:Qt模块架构全景
2.1 Qt模块分层图
┌─────────────────────────────────────────────────────────────┐
│ Qt 6 模块全景 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 应用层 (你的代码) │ │
│ │ CAE 前后处理 / 求解器集成 / 网格可视化 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Qt Widgets│ │ Qt Quick │ │ Qt 3D │ │Qt Charts │ │
│ │ 经典控件 │ │ QML声明式│ │ 3D场景图 │ │ 图表绘制 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Qt GUI (底层图形) │ │
│ │ QWindow / QScreen / QSurface / QPainter │ │
│ │ QOpenGLWidget / QOpenGLFunctions / QVulkanWindow │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Qt Core (核心) │ │
│ │ QObject / 信号槽 / 事件循环 / MOC │ │
│ │ QThread / QVariant / QSettings / QFile │ │
│ │ QString / QByteArray / QJsonDocument │ │
│ │ QTimer / QProcess / QPluginLoader │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Qt 附加模块 (按需链接) │ │
│ │ Qt Network │ Qt SQL │ Qt XML │ Qt Concurrent │ │
│ │ Qt OpenGL │ Qt PrintSupport │ Qt Test │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘2.2 CAE开发的核心模块
┌─────────────────────────────────────────────────────────────┐
│ CAE开发必备Qt模块 (按重要度排序) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 模块 用途 在CAE中的位置 │
│ ────────────── ─────────────────────── ───────────────── │
│ Qt::Core QObject/信号槽/事件循环 ★★★★★ 一切的基础 │
│ Qt::Widgets 经典控件/MDI/停靠窗口 ★★★★★ 主界面 │
│ Qt::OpenGL 3D视口/网格渲染 ★★★★★ 前后处理 │
│ Qt::Concurrent 并行网格操作 ★★★★ 性能关键 │
│ Qt::Network 远程求解/许可证 ★★★ 分布式 │
│ Qt::Xml 求解器输入文件解析 ★★★ 数据交换 │
│ Qt::Sql 材料数据库/项目管理 ★★☆ 辅助 │
│ Qt::Charts 收敛曲线/X-Y图 ★★★ 后处理 │
│ Qt::PrintSupport 报告打印/PDF输出 ★★☆ 报告 │
│ Qt::Test 单元测试 ★★★ 质量 │
│ Qt::Linguist 国际化翻译 ★★☆ i18n │
│ │
│ 第3方集成: │
│ VTK (QVTKOpenGLNativeWidget) 科学可视化管线 │
│ OpenCASCADE 几何内核 │
│ Eigen 线性代数 │
│ PETSc/Trilinos 并行求解 │
│ │
└─────────────────────────────────────────────────────────────┘2.3 Qt6 vs Qt5 — 迁移要点
┌─────────────────────────────────────────────────────────────┐
│ Qt5 → Qt6 关键变化 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 变化项 Qt5 Qt6 │
│ ─────────────── ─────────────────── ──────────────────── │
│ 构建系统 qmake/CMake CMake优先;qmake仍可用│
│ CMake包名 find_package(Qt5) find_package(Qt6) │
│ 需要指定Components 需要指定Components │
│ │
│ 元对象系统 moc 处理 .h 新增 moc --require- │
│ complete-type │
│ │
│ QTextCodec Qt Core 移至Core5Compat; │
│ 新代码用Converter │
│ QString 内部 UTF-16代码单元 仍为UTF-16代码单元 │
│ │
│ QDesktopWidget 存在 移除,用QScreen │
│ QRegExp 存在 替换为QRegularExpression│
│ │
│ 容器类 QList 是指针数组 QList 大小<=指针 │
│ QVector 存在 QVector = QList │
│ │
│ QML/Qt Quick Qt 5时代版本化导入 Qt 6继续演进, │
│ 不宜概括为Quick 3 │
│ │
│ OpenGL模块 默认存在 独立模块,显式链接 │
│ │
│ 平台要求 随具体Qt 5版本变化 随Qt 6小版本变化, │
│ 以目标版本文档为准 │
│ │
│ ★ 新项目通常优先 Qt 6 + CMake;遗留项目按依赖与平台迁移 │
│ │
└─────────────────────────────────────────────────────────────┘第3部分:Qt与标准C++的关系
3.1 MOC到底是什么?
这是理解 Qt 的第一个门槛。MOC(Meta-Object Compiler,元对象编译器)是 Qt 构建工具链的重要代码生成步骤之一;Qt 还包含 UIC、RCC、QML 类型注册等其他生成流程,因此不应称为“唯一非标准扩展”。
┌─────────────────────────────────────────────────────────────┐
│ Qt的编译流程(含MOC预处理) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 你写的代码 │
│ ┌──────────────────────────────────────────────────┐ │
│ │ // mesh_viewer.h │ │
│ │ class MeshViewer : public QWidget { │ │
│ │ Q_OBJECT ← MOC 识别标记 │ │
│ │ signals: │ │
│ │ void meshChanged(Mesh* mesh); │ │
│ │ private slots: │ │
│ │ void onLoadClicked(); │ │
│ │ }; │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ │
│ 2. MOC 预处理 (moc mesh_viewer.h -o moc_mesh_viewer.cpp) │
│ ┌──────────────────────────────────────────────────┐ │
│ │ // moc_mesh_viewer.cpp (自动生成,永远不要编辑) │ │
│ │ const QMetaObject MeshViewer::staticMetaObject = │ │
│ │ QMetaObject({... 元信息表 ...}); │ │
│ │ │ │
│ │ void MeshViewer::meshChanged(Mesh* m) { │ │
│ │ QMetaObject::activate(this, signal_index, m);│ │
│ │ } │ │
│ │ │ │
│ │ int MeshViewer::qt_metacall(...) { │ │
│ │ // 信号/槽/属性的运行时调度表 │ │
│ │ } │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ │
│ 3. C++ 编译器 一起编译 mesh_viewer.cpp + moc_mesh_viewer.cpp│
│ ↓ │
│ 4. 链接器 生成最终可执行文件 │
│ │
└─────────────────────────────────────────────────────────────┘MOC 做了什么?
- 为 signals 自动生成函数体 — 你只声明 signal,MOC 生成其实现(调用 QMetaObject::activate)
- 生成静态元对象(staticMetaObject) — 包含类名、信号/槽/属性的字符串表和索引
- 生成 qt_metacall() — 运行时信号槽分发的核心调度函数
- 生成 qt_static_metacall() — 编译时已知的槽函数调用(新式 connect 用的就是这个)
3.2 Qt的"非标准"扩展
// Qt 对 C++ 的扩展(都在宏里,最终展开为标准C++)
// Q_OBJECT 宏展开后大约包含:
#define Q_OBJECT \
public: \
static const QMetaObject staticMetaObject; \
virtual const QMetaObject *metaObject() const; \
virtual void *qt_metacast(const char *); \
virtual int qt_metacall(QMetaObject::Call, int, void **); \
QT_TR_FUNCTIONS /* 国际化 tr() */ \
private: \
Q_OBJECT_NO_OVERRIDE_WARNING /* 禁止编译器警告 */
// signals: → 展开为 public:
// slots: → 展开为空(只是标记给 MOC 看的)
// emit → 展开为空(纯粹文档作用,让代码意图更清晰)
// Q_PROPERTY 示例
class MeshPart : public QObject {
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
public:
QString name() const { return m_name; }
void setName(const QString &n) {
if (m_name != n) { m_name = n; emit nameChanged(n); }
}
signals:
void nameChanged(const QString &newName);
private:
QString m_name;
};3.3 Qt对象模型 vs 标准C++对象模型
| 特性 | 标准C++ | Qt (QObject派生类) |
|---|---|---|
| 运行时类型信息 | typeid() / dynamic_cast | qobject_cast<T>() / metaObject()->className() |
| 动态属性 | 无 | setProperty() / property() (QVariant) |
| 信号/槽 | 需要手写回调/观察者 | signals: / slots: + connect() |
| 父子所有权 | RAII / unique_ptr | 对象树:parent删child自动delete |
| 对象名称 | 无 | setObjectName() / findChild<T>() |
| 线程亲缘性 | 无 | QObject::thread() / moveToThread() |
| 内省 (Introspection) | 无 | QMetaObject / QMetaProperty / QMetaMethod |
| 编译 | 纯C++编译器 | 需要MOC预处理(自动化的) |
3.4 CMake 中配置 Qt(Qt6 标准方式)
# CMakeLists.txt — CAE骨架项目的Qt配置
cmake_minimum_required(VERSION 3.21)
project(FastCAE VERSION 0.1.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 自动运行 MOC (处理 Q_OBJECT)
set(CMAKE_AUTOMOC ON)
# 自动处理 .ui 文件 (Qt Designer 界面)
set(CMAKE_AUTOUIC ON)
# 自动处理 .qrc 文件 (资源文件)
set(CMAKE_AUTORCC ON)
# 查找 Qt6 模块
find_package(Qt6 REQUIRED COMPONENTS
Core
Widgets
OpenGLWidgets
Concurrent
Xml
)
# CAE骨架可执行文件
qt_add_executable(FastCAE
src/main.cpp
src/main_window.h src/main_window.cpp
src/mesh_viewport.h src/mesh_viewport.cpp
src/model_document.h src/model_document.cpp
src/solver_worker.h src/solver_worker.cpp
resources/resources.qrc
)
target_include_directories(FastCAE PRIVATE src/)
target_link_libraries(FastCAE PRIVATE
Qt6::Core
Qt6::Widgets
Qt6::OpenGLWidgets
Qt6::Concurrent
Qt6::Xml
)
# 也可以链接第三方
# find_package(VTK REQUIRED)
# target_link_libraries(FastCAE PRIVATE VTK::GUISupportQt)3.5 最小CAE骨架main.cpp
// main.cpp — 每个Qt应用程序的入口
#include <QApplication>
#include "main_window.h"
int main(int argc, char *argv[])
{
// QApplication 管理GUI事件循环
// 对于非GUI的求解器CLI工具,用 QCoreApplication
QApplication app(argc, argv);
// 设置应用程序元信息(影响 QSettings 路径等)
app.setOrganizationName("FastCAE");
app.setApplicationName("FastCAE PrePost");
app.setApplicationVersion("0.1.0");
MainWindow window;
window.setWindowTitle("FastCAE - FEA Pre/Post Processor");
window.resize(1600, 900);
window.show();
// app.exec() 进入事件循环 — 阻塞在这里直到窗口关闭
return app.exec();
}第4部分:本系列学习路径
4.1 学习路径总览
本系列采用“8 篇主线 + 9 篇专题”的结构。主线负责建立完整 CAE 应用认知,topics/ 目录专门解释版本敏感、跨线程、生命周期、格式兼容和生产化边界。建议在读完对应主章后立即阅读其专题。
┌─────────────────────────────────────────────────────────────┐
│ Qt/CPP CAE 开发学习路径 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 你现在在这里 → [00] Qt在CAE开发中的角色与核心机制总览 │
│ ↓ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 核心机制 (必学,按顺序) │ │
│ │ [01] 信号槽机制深度解析 ← Qt最核心的通信机制 │ │
│ │ ↓ │ │
│ │ [02] 对象树与内存管理 ← QObject的生命周期 │ │
│ │ ↓ │ │
│ │ [03] CAE开发常用核心API实战 ← 工具箱 │ │
│ └───────────────────────────────────────────────────────┘ │
│ ↓ ↓ ↓ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │[04] │ │[05] │ │[07] │ │
│ │Model/View│ │多线程与 │ │3D可视化 │ │
│ │架构 │ │求解器集成│ │与交互 │ │
│ └────┬─────┘ └────┬─────┘ └──────┬───────┘ │
│ └──────────────┼──────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 综合应用 │ │
│ │ [06] CAE软件架构实战模式 ← 把前面串起来 │ │
│ │ ↓ │ │
│ │ [08] 实战案例:FEA前后处理器 ← 最终的综合案例 │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ 知识点分布: │
│ • 信号槽 (01 + 贯穿全系列) │
│ • 对象树/内存 (02 + 贯穿全系列) │
│ • CAE API工具箱 (03) │
│ • 架构模式 (04 + 06) │
│ • 性能/多线程 (05) │
│ • 可视化 (07) │
│ • 综合实战 (08) │
│ │
└─────────────────────────────────────────────────────────────┘4.2 前置知识检查清单
在深入学习本系列之前,确认你具备:
- [ ] C++ 基础扎实:类、继承、多态、模板、RAII
- [ ] 了解 CMake 基本语法(
add_executable、target_link_libraries) - [ ] 对工业软件有基本了解(读过 Overview)
- [ ] 了解C++项目构建基础(读过 Cpp Project Fundamentals 更好)
- [ ] 有一份可编译运行的 Qt6 开发环境(SDK + CMake + 编译器)
4.3 本系列的设计哲学
┌─────────────────────────────────────────────────────────────┐
│ 本系列笔记的三个坚持 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 每个概念都落到CAE场景 │
│ 不讲"信号槽的概念是什么",而是讲"网格更新后怎么通知 │
│ 视口刷新" │
│ │
│ 2. 每个API都有真实代码样例 │
│ 不是伪代码,是可编译的 C++/Qt 代码片段 │
│ │
│ 3. 每个陷阱都附错误信息原文 │
│ 让你在 StackOverflow / Google 上能搜得到 │
│ │
└─────────────────────────────────────────────────────────────┘核心总结
总结1:Qt 的优势与边界
Qt 对跨平台 C++ 桌面软件、成熟 Widgets、事件驱动和 VTK 集成具有明显优势,但不是所有 CAE 项目的唯一答案。技术选型还应比较团队经验、许可证、无障碍支持、部署体积、目标平台、原生体验和 Web 协作需求。Qt 与 C++ 求解器可以直接集成,但跨模块调用是否“零开销”取决于数据复制、线程和进程边界。
总结2:MOC是编译时魔法,不是运行时黑盒
MOC 读取包含 Q_OBJECT 等宏的声明并生成元对象信息、信号实现和调用分派所需代码。signals/slots 宏本身会参与普通 C++ 编译,但完整能力依赖生成代码。理解这一点有助于定位漏掉 AUTOMOC、生成文件未参与 target、类定义未被扫描等构建问题。
总结3:Qt模块分工明确
Qt::Core (QObject + 信号槽 + 事件循环) → 一切的基础
Qt::Widgets (窗口/控件/MDI) → 经典桌面UI
Qt6::OpenGLWidgets (QOpenGLWidget) → 3D视口
Qt::Concurrent (map/reduce/run) → CPU并行章节测试
测试1:框架选择
以下哪个不是CAE软件普遍选择Qt的原因? A. Qt是C++原生框架,可以直接调用求解器代码 B. Qt提供信号槽机制,适合异步GUI更新 C. Qt的QML语言比C++更容易编写高性能求解器 D. Qt一套代码可以编译到Windows和Linux
测试2:MOC的作用
MOC(元对象编译器)的主要输出是什么? A. 将C++代码翻译为Python B. 生成信号函数体、元对象表、qt_metacall调度函数 C. 将.ui文件转为C++代码 D. 将Qt代码转为标准C++(去掉signals/slots宏)
测试3:Qt6迁移
Qt6相比Qt5的一个重要变化是什么? A. 信号槽机制被移除,改用std::function B. qmake被移除,只能用CMake C. QTextCodec离开Qt Core,新代码通常使用QStringConverter相关API D. QObject被移除,改用std::object
测试4:编译流程
在CMake中配置set(CMAKE_AUTOMOC ON)的作用是什么? A. 自动将.pro文件转为CMakeLists.txt B. 自动调用MOC处理所有包含Q_OBJECT的头文件 C. 自动链接所有Qt模块 D. 自动生成main.cpp
测试5:CAE应用入口
对于只做计算(无GUI)的求解器命令行工具,应该用什么替代QApplication? A. QGuiApplication B. QApplication 加 -nogui 参数 C. QCoreApplication D. 直接写 int main() 不需要任何Qt应用对象
参考答案
测试1答案
答案:C。QML是声明式UI语言,适合编写界面而非高性能求解器。求解器核心算法仍然用C++编写(带Eigen/PETSc等库),QML只是另一种UI实现方式。事实上大多数CAE软件用Qt Widgets而非QML。
测试2答案
答案:B。MOC解析带Q_OBJECT宏的头文件,生成:
- 信号函数的实现体(调用
QMetaObject::activate) staticMetaObject静态元对象(包含类名、信号/槽/属性的字符串表)qt_metacall()运行时调度函数 选项C是UIC(用户界面编译器)的工作。
测试3答案
答案:C。Qt 6 将 QTextCodec 放入兼容模块,新代码通常使用 QStringConverter、QStringDecoder 和 QStringEncoder。这不表示 QString 改成 UTF-8;它仍保存 UTF-16 代码单元。qmake 仍可用,但 Qt 6 新项目通常优先 CMake。
测试4答案
答案:B。CMAKE_AUTOMOC ON让CMake自动检测所有包含Q_OBJECT宏的头文件,并在编译前自动调用MOC处理它们,生成moc_*.cpp文件加入编译。不需要手动写qt_wrap_cpp。
测试5答案
答案:C。QCoreApplication提供事件循环但不初始化GUI子系统。对于纯计算的求解器CLI工具,它是正确的选择——仍然可以使用信号槽、QTimer、QProcess等,只是不创建窗口。QApplication继承自QGuiApplication,后者继承自QCoreApplication。
相关笔记
- Technical Stack - 工业软件技术栈总览(Qt在其中的位置)
- Cpp Project Fundamentals - C++项目构建基础
- Project Structure Thirdparty Cmake - CMake项目结构与第三方库集成
- Cae Basics - CAE仿真基础概念
- Architecture - CAE软件架构详解
下一步学习
- [ ] 阅读 01 - 信号槽机制深度解析 — 理解Qt最核心的通信机制
- [ ] 搭建你的Qt6+CMake开发环境,编译运行上面的骨架代码
- [ ] 浏览 Qt6 官方文档,建立对各模块的感性认识
学习状态:🟡 开始学习
执行链总图
main
-> QApplication constructed
-> build QObject ownership tree
-> connect signals/slots
-> app.exec event loop
-> native event translated
-> QObject event/slot
-> state/model update
-> update/paint request
-> quit requested
-> stop workers and queued work
-> destroy windows/object tree
-> QApplication/runtime teardown这张图把 Qt 的三条主线串在一起:事件循环决定代码何时执行,对象树决定谁清理谁,线程亲和性决定 queued 工作在哪执行。任何崩溃/卡死都应先定位属于哪条线。
面试连续追问
问:Qt 为什么需要 moc?
答:标准 C++ 不提供 Qt 所需的运行时 signal/slot、property 和类元数据;moc 根据声明生成额外 C++ 元对象代码,与普通源文件一起编译链接。
问:Qt GUI 为什么通常单线程?
答:窗口系统与 QObject 事件状态要求确定亲和线程,单 GUI event loop 避免控件内部状态到处加锁;计算可并行,但 UI 提交回 GUI 线程。
问:事件驱动是否等于异步?
答:事件循环支持异步排队,但 Direct signal/普通函数调用仍同步;必须看具体连接和 API。
自测与答案
- app.exec 做什么? 答:进入主事件循环,分发 native/posted events、timer 与 queued 调用。
- QObject parent 与线程亲和性的关系? 答:父子必须同线程,带 parent 的对象不能单独迁移。
- 耗时任务完成后怎样更新 UI? 答:以 queued signal/invoke 把不可变结果或 ID 交回 GUI 线程。