2. Qt Quick技术栈概览
在正式进入 Qt Quick 项目交付之前,必须先建立一张清晰的“技术栈地图”。很多初学者把 QML 当成一门独立语言来学,把 C++ 当成另一套完全无关的东西,结果在项目里遇到“界面能跑但数据传不进去”“逻辑写在 QML 里越写越乱”“构建报错不知道是 qmake 还是 CMake 的问题”时,就无从下手。本节的目标,是把 Qt Quick 技术栈中六个关键角色——QML、JavaScript、C++、Qt Quick Controls、Qt Creator、构建系统——放到同一张关系图里,讲清它们各自负责什么、通过什么机制连接、在交付项目中如何分工。
一、核心原理:分层协作,而不是互相替代
Qt Quick 的本质是一个“声明式 UI + 命令式逻辑 + 原生能力”的混合框架。它并不是要用 QML 取代 C++,而是让不同层做各自最擅长的事。可以把它理解成一条从“用户看到什么”到“机器执行什么”的纵向链路:
- QML:声明式语言,负责描述界面结构、属性绑定、动画和状态。它回答的是“界面长什么样、随状态怎么变”。
- JavaScript:QML 的内嵌脚本能力,负责轻量逻辑、事件处理、表达式计算。它回答的是“点击后做什么、条件怎么判断”。
- C++:负责性能敏感计算、系统调用、硬件接口、数据模型和业务核心。它回答的是“底层能力从哪来、复杂数据怎么管”。
- Qt Quick Controls:基于 QML 的控件库,提供 Button、Slider、TableView、Dialog 等标准控件与样式,回答的是“常用交互组件不用从零写”。
- Qt Creator:集成开发环境,负责编辑、调试、预览、部署,回答的是“开发者在哪里写、在哪里调”。
- 构建系统:qmake 或 CMake,负责把 QML 资源、C++ 源码、依赖库组织成可执行程序,回答的是“代码怎么变成能交付的产物”。
这六者不是并列的六个工具,而是有明确依赖方向的分层结构。下面的 SVG 用一张架构关系图把它们串起来,重点看箭头方向:QML 与 JavaScript 在表现层,C++ 在能力层,Controls 是表现层的组件库,Qt Creator 与构建系统则贯穿开发与交付。
二、方法流程:一个界面从点击到数据落地的完整路径
理解分层之后,再看一次真实的数据流,就能把六个角色串起来。假设界面上有一个“刷新”按钮,点击后从 C++ 数据模型读取最新列表并显示:
- 用户在 QML 界面点击
Button(来自 Qt Quick Controls)。 - 按钮的
onClicked触发 JavaScript 处理函数。 - JavaScript 调用 C++ 通过
Q_INVOKABLE暴露的方法,或修改绑定到 C++ 属性的值。 - C++ 执行实际业务逻辑,更新
Q_PROPERTY或发出信号。 - QML 中绑定该属性的表达式自动重新求值,界面刷新。
- Qt Creator 负责调试这一整条链路,构建系统负责把 QML 资源与 C++ 编译进同一个产物。
这条链路说明一个关键点:QML 不直接“拥有”业务数据,C++ 也不直接“画”界面。两者通过属性绑定和信号槽通信,这是 Qt Quick 项目可维护性的根基。
三、案例场景:一个设备监控面板的分工
假设要交付一个工业设备监控面板,包含实时曲线、参数设置、报警列表。合理的分工如下:
| 模块 | 技术选择 | 原因 |
|---|---|---|
| 主界面布局、导航 | QML + Qt Quick Controls | 声明式描述,控件现成,改版快 |
| 按钮点击、表单校验 | JavaScript | 轻量逻辑,无需编译,迭代快 |
| 设备通信、协议解析 | C++ | 性能与系统调用,QML 不适合 |
| 实时曲线数据源 | C++ 模型 + QML 绑定 | 数据量大,需高效更新与解耦 |
| 编译、打包、部署 | CMake + Qt Creator | 统一构建流程,便于 CI 与交付 |
四、误区与复盘:最常见的三类错误
误区一:把所有逻辑都写进 QML/JavaScript。 初期确实快,但一旦涉及复杂状态、并发、性能,QML 会变得难以调试。正确做法是:界面状态留在 QML,业务规则下沉到 C++。
误区二:认为 Qt Quick Controls 就是全部控件。 Controls 提供的是标准控件与样式,复杂可视化(如自定义仪表盘、曲线)仍需基于 Item、Canvas 或 Shape 自行绘制。
误区三:忽视构建系统对 QML 资源的处理。 QML 文件若未正确加入资源系统(qt_add_qml_module 或 .qrc),运行时会出现“模块找不到”。交付前必须确认 QML 已被打包进产物。
复盘建议:在项目初期就画一张类似本节的分层图,明确每个模块归属哪一层。凡是“界面怎么变”的问题归 QML,凡是“数据从哪来、怎么算”的问题归 C++,凡是“怎么编译、怎么打包”的问题归构建系统。边界清晰,交付才稳。
# CMake 中注册 QML 模块的典型写法(Qt 6)
qt_add_qml_module(appMonitor
URI Monitor
VERSION 1.0
QML_FILES
Main.qml
pages/Dashboard.qml
pages/Settings.qml
SOURCES
devicecontroller.cpp
devicemodel.cpp
)