Qt5 Cadaques - Qt Quick/QML 编程全指南

一本开源的 Qt5 / Qt Quick / QML 编程教程,从基础语法到高级渲染特效、C++ 扩展和 Python 绑定,内容全面且实战导向。

书籍概览

  • 作者: Jonas Ryannel, Johan Thelin
  • 版本: Release master(基于 Qt 5.12,2020 年 12 月更新)
  • 定位: 从入门到进阶的 Qt Quick/QML 实战教程
  • 特点: 每章都有配套代码示例,循序渐进,强调动手实践
  • 章节结构: 21 章,从 QML 基础到 C++/Python 扩展,覆盖移动应用开发

核心知识体系

一、Qt5 基础架构

1. Qt 模块体系

Qt5 分为两大模块组:

Qt Essentials(核心必需模块):

  • QtCore — 核心非图形类,被其他模块依赖
  • QtGUI — GUI 基础类,包含 OpenGL
  • QtQml — QML 和 JavaScript 语言支持
  • QtQuick — 声明式框架,构建高度动态的自定义 UI
  • Qt Quick Controls 2 — 轻量级 QML 控件(按钮、标签、滑块等)
  • Qt Quick Layouts — 布局管理器
  • QtNetwork — 网络编程
  • QtMultimedia — 音视频/相机
  • QtSQL — 数据库集成
  • QtWidgets — 传统 C++ Widget 库

Qt Add-On(附加模块):

  • Qt 3D — 3D 图形编程
  • Qt Bluetooth — 蓝牙
  • Qt Canvas 3D — 类 OpenGL 的 3D 绘制
  • Qt Graphical Effects — 图形特效
  • Qt Location — 地图与导航
  • Qt Sensors — 传感器
  • Qt Purchasing — 应用内购买

2. Qt Project 与开源社区

Qt 是一个精英治理(meritocratic)的开源社区,最大贡献者是 The Qt Company(同时持有商业授权)。

二、QML 语言核心

1. QML 语法基础

QML 是一种声明式语言,类似 HTML,但专为构建动态 UI 设计。

核心概念:

  • 元素 (Element): QML 的基本构建块,如 Rectangle、Text、Image
  • 属性 (Property): 键值对,有明确类型,如 width: 100、color: "#FF0000"
  • id: 特殊标识符,用于在文档内引用元素,不可在运行时修改
  • 锚定 (Anchors): 声明元素间的几何关系(left/right/top/bottom/centerIn/fill 等)
  • 信号与槽 (Signals & Slots): 事件驱动机制,命名惯例 on<SignalName>

属性的 9 种形态:

  1. id — 文档内唯一标识符(非字符串,是语法关键字)
  2. 普通赋值 — width: 100
  3. 属性绑定 (Binding) — height: 2 * width,依赖变化时自动更新(“契约式”)
  4. 自定义属性 — property int times: 24
  5. 属性别名 (Alias) — property alias anotherTimes: thisLabel.times,用于向外暴露内部属性
  6. 字符串拼接绑定 — text: "Greetings " + times
  7. 分组属性 — font.family: "Ubuntu",结构化属性分组
  8. 附加属性 — KeyNavigation.tab: otherLabel,全局属性附加到元素上
  9. 属性变更信号处理器 — onHeightChanged: console.log(height)

重要警告: QML 的绑定(:)和 JavaScript 赋值(=)有本质区别。绑定是”终身契约”,一旦用 JS 赋值给同一属性,绑定就被破坏了!这是 QML 新手最常见的坑。

2. 基本元素

Item(所有视觉元素的基类):

  • 几何属性: x, y, width, height, z
  • 布局: anchors(锚定系统)
  • 按键: focus, Key, KeyNavigation
  • 变换: scale, rotation, transformOrigin
  • 视觉: opacity, visible, clip, smooth
  • 状态: states, transitions

常用视觉元素:

  • Rectangle — 矩形,支持填充色、边框、圆角(radius)
  • Text — 文本,支持富文本、换行、省略
  • Image — 图片,支持 fillMode(PreserveAspectFit / PreserveAspectCrop 等)
  • MouseArea — 鼠标/触摸交互区域,onClicked 等信号

3. 组件 (Components)

QML 支持自定义可复用组件。一个 .qml 文件就是一个组件,文件名即组件名(首字母大写)。通过 property alias 向外暴露内部属性。

三、动画与状态

1. 动画系统

QML 提供丰富的动画类型,核心是 Animation 及其子类:

  • PropertyAnimation / NumberAnimation — 数值属性动画
  • ColorAnimation — 颜色动画
  • RotationAnimation — 旋转动画(处理 360° 环绕)
  • PathAnimation — 沿路径运动

三种使用动画的方式:

  1. Behavior on — 属性变化时自动触发动画(最常用)
  2. 直接启动 — animation.start() 手动控制
  3. Transition — 状态切换时的过渡动画

2. 状态与过渡 (States & Transitions)

  • states 列表定义不同状态
  • State 包含 PropertyChanges,描述状态间的属性差异
  • transitions 定义状态切换时的动画过渡
  • when 条件触发状态切换

四、Qt Quick Controls 2

提供标准 UI 控件库:按钮、标签、滑块、输入框、下拉菜单等。特点:轻量、高性能、支持多种样式(Material、Universal、Imagine 等)。

Imagine Style: 基于图像的样式系统,可以完全自定义控件外观,适合打造品牌化 UI。

五、Model-View-Delegate 架构

Qt Quick 的列表/视图采用经典的 M-V-D 模式:

  • Model (模型): 数据源,可以是简单数组、ListModel、C++ 自定义模型
  • View (视图): 显示数据的容器(ListView、GridView、Repeater 等)
  • Delegate (委托): 定义每个数据项如何渲染,是模型的可视化表达

关键概念:

  • ListView — 纵向/横向滚动列表
  • GridView — 网格视图
  • Repeater — 非滚动的重复器
  • 动态视图支持懒加载,只创建可见区域的 delegate
  • delegate 中可直接访问 model 的角色数据

六、高级图形

1. Canvas 元素

提供类似 HTML5 Canvas 的 2D 绘制 API,支持:

  • 路径、渐变、阴影、图像
  • 变换(平移/旋转/缩放)
  • 合成模式(Composition Modes)
  • 像素缓冲区(像素级操作)
  • 可从 HTML5 Canvas 迁移过来

2. 粒子系统 (Particle System)

用于创建烟、火、火花等动态视觉效果:

  • ParticleSystem — 粒子系统管理器
  • Emitter — 粒子发射器
  • ParticlePainter / ImageParticle — 粒子渲染器
  • 影响器: Gravity(重力)、Friction(摩擦)、Turbulence(紊流)、Wander(漫游)
  • 粒子组与组转换 — 实现火箭爆炸等多阶段效果

3. 着色器特效 (Shader Effects)

通过 ShaderEffect 和 ShaderEffectSource 直接调用 GPU 的 OpenGL 着色器:

  • 顶点着色器 (Vertex Shader): 操作多边形顶点,控制 3D 变换
  • 片段着色器 (Fragment Shader): 逐像素计算颜色,实现扭曲、波纹等特效
  • 使用 GLSL 语言编写,通过 QML 属性与着色器交互
  • Qt 提供 QtGraphicalEffects 模块内置多种特效(模糊、发光、色相等)

七、多媒体与网络

1. 多媒体

  • MediaPlayer — 播放音频/视频
  • SoundEffect — 短音效
  • VideoOutput — 视频渲染
  • Camera — 相机捕获

2. 网络编程

HTTP 请求: 使用 XMLHttpRequest(和浏览器 API 一致)发起 GET/POST/PUT/DELETE 请求

REST API 交互模式:

  • 将 API 封装为 JS 服务模块(如 colorservice.js)
  • 使用 XMLHttpRequest + JSON 解析
  • 封装 CRUD 操作接口供 QML 调用

其他网络能力:

  • XmlListModel — XML 数据模型
  • WebSockets — 实时双向通信
  • OAuth — 第三方登录授权
  • 本地文件访问

八、存储

  • Settings: 键值对持久化(类似 QSettings)
  • LocalStorage / SQL: 嵌入式 SQLite 数据库
  • 其他存储 API

九、动态 QML

  • 动态加载组件: Loader 元素、Qt.createComponent() + createObject()
  • 动态创建/销毁对象: 运行时生成 QML 对象
  • 跟踪动态对象: 管理动态创建的对象生命周期

十、JavaScript 与 QML

QML 深度集成 JavaScript:

  • 属性绑定使用 JS 表达式
  • 信号处理器中写 JS 代码
  • 可定义 JS 函数
  • 支持 JS 模块导入
  • 注意:JS 赋值会破坏 QML 绑定(见前文警告)

十一、Qt 与 C++

1. QObject 基石

QObject 是 Qt 对象系统的基类,提供两大能力:

  • 内省 (Introspection): 知道自己的类名、属性、方法、信号
  • 内存管理: 父子对象树,父对象销毁时自动销毁子对象

Q_OBJECT 宏: 启用元对象系统,必须放在类的私有区开头

Q_PROPERTY 宏: 声明属性,格式:

Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
  • READ — 读取函数
  • WRITE — 写入函数(可选,只读属性没有)
  • NOTIFY — 变更通知信号(QML 绑定依赖它)

信号与槽: Qt 的核心通信机制,松耦合。用 connect() 连接。

小技巧: Q_GADGET 宏是 Q_OBJECT 的轻量版,可用于非 QObject 派生类暴露属性和可调用方法,但不能有信号。

2. 构建系统

qmake: Qt 原生构建系统,使用 .pro 项目文件

  • QT += qml quick — 添加 QML/Quick 模块
  • TEMPLATE = app / lib / subdirs — 应用/库/子目录
  • 支持 scope(平台条件编译):unix { ... }、macx { ... }
  • 支持 shadow build(源码外构建)

CMake: 跨平台构建系统,适合大型项目

  • find_package(Qt5Core) — 查找 Qt 模块
  • CMAKE_AUTOMOC ON — 自动调用 MOC
  • target_link_libraries(target Qt5::Core) — 链接 Qt 库

3. 扩展 QML 与 C++ 插件

可以用 C++ 编写自定义 QML 类型和插件:

  • 继承 QQmlExtensionPlugin 编写插件
  • 在 qmldir 文件中注册插件
  • QML 运行时动态加载

典型示例: FileIO 插件——在 QML 中读写本地文件

十二、Felgo 框架

Felgo(原 V-Play)是基于 Qt 的跨平台应用/游戏开发框架:

核心特性:

  • 热重载 (QML Hot Reloading) — 代码修改即时生效
  • 密度无关像素 — dp() 用于尺寸,sp() 用于字体
  • 自适应导航 — 桌面显示侧边栏,移动显示底部 Tab
  • 丰富的内置组件: Navigation, NavigationStack, ListPage, SimpleRow 等
  • 大量插件: 广告、内购、通知、分析、Firebase、云存储、AR 等

开发体验: 内置 Live Client,支持手机端实时预览

十三、Qt for Python (PySide2)

Qt 的官方 Python 绑定,让 Python 开发者使用 Qt:

基本用法:

from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
 
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.load(QUrl("main.qml"))
app.exec_()

向 QML 暴露 Python 对象:

  • 继承 QObject
  • 用 Signal(类型) 声明信号
  • 用 @Slot() 装饰器声明槽
  • 通过 engine.rootContext().setContextProperty("name", obj) 暴露为全局变量

已知限制:

  • Python 信号的参数名无法传递到 QML(需要 workaround)
  • Python 中没有 invokable 概念,所有可调用方法必须是槽

关键概念速查

概念说明
属性绑定height: 2 * width,响应式更新,是契约而非一次性赋值
锚定系统anchors 声明元素间几何关系,替代手动坐标计算
信号槽Qt 的事件驱动核心,松耦合通信
M-V-DModel-View-Delegate,数据与视图分离
QObjectQt 对象系统基类,提供内省和内存管理
MOC元对象编译器,处理 Q_OBJECT 等宏生成 C++ 代码
ShaderEffectGPU 着色器,实现高级视觉特效
Behavior on属性变化自动触发动画的便捷语法
property alias组件向外暴露内部属性的方式
隐式共享QString 等 Qt 类的写时拷贝内存优化

学习路径建议

  1. 入门: 第 1-4 章 — 认识 Qt5,安装环境,QML 语法基础
  2. 进阶: 第 5-7 章 — 动画、控件、MVD 模式
  3. 实战: 第 8 章 — 用 Felgo 做一个完整的消息应用
  4. 高级图形: 第 9-11 章 — Canvas、粒子系统、着色器
  5. 全栈能力: 第 12-15 章 — 多媒体、网络、存储、动态 QML
  6. 性能扩展: 第 16-18 章 — JS 集成、C++ 扩展、编写 QML 插件
  7. 生态: 第 19-20 章 — Felgo 插件、Qt for Python

与其他知识的关联

  • SICP — QML 的声明式范式与函数式编程思想相通
  • 程序员修炼之道 — Qt 的”信号槽”松耦合设计体现了务实的工程哲学
  • 重构 — QML 组件化思维与重构中的”提取函数/类”异曲同工

个人备注

  • 这本书是开源免费的,可以作为 Qt Quick/QML 的入门首选教程
  • Felgo 部分有较强的商业导向,但热重载和密度无关像素的设计思想值得借鉴
  • 如果做移动应用,Felgo 相比原生 Qt Quick 能节省大量样板代码
  • C++ 扩展章节(17-18章)是理解 Qt 底层的关键,值得深入