适合人群: 了解 Qt 基础,想搞清楚两种 UI 框架区别的开发者
前言
Qt 提供了两套完全不同的 UI 技术路线:Qt Quick(QML) 和 Qt Widgets(C++)。很多新手在项目开始时就卡在这个选择上,不知道该学哪个、用哪个。
本文从渲染原理、开发体验、适用场景三个维度做完整对比,帮你做出清晰判断——而不是给你一个模糊的"看情况"。
一、两种技术的本质区别
Qt Widgets
Qt Widgets 诞生于 1990 年代,是 Qt 最早的 UI 系统。它基于操作系统的原生控件体系:
- 按钮、输入框、菜单等控件由操作系统负责渲染
- 外观与系统原生应用一致(Windows 上看起来像 Windows 应用,macOS 上看起来像 Mac 应用)
- 用 C++ 编写,代码风格偏命令式
// Qt Widgets 示例:创建一个按钮
QPushButton *button = new QPushButton("点我", this);
button->setGeometry(100, 100, 120, 40);
connect(button, &QPushButton::clicked, this, &MainWindow::onButtonClicked);
Qt Quick
Qt Quick 诞生于 2010 年,是 Qt 为现代 UI 设计的全新系统:
- 所有元素由 Qt 自己的渲染引擎(基于 OpenGL / Vulkan / Metal)绘制,不依赖操作系统控件
- 外观完全由开发者控制,默认不带任何平台风格
- 用 QML 编写,声明式语法,更接近现代前端开发
// Qt Quick 示例:创建一个按钮
Button {
x: 100; y: 100
width: 120; height: 40
text: "点我"
onClicked: console.log("被点击了")
}
二、核心对比
2.1 渲染方式
| Qt Widgets | Qt Quick | |
|---|---|---|
| 渲染引擎 | 操作系统原生控件 | Qt 自有 GPU 渲染引擎 |
| 外观 | 跟随系统主题 | 完全自定义 |
| 动画性能 | 有限,复杂动画吃力 | 流畅,GPU 加速 |
| 高 DPI 支持 | 需要手动适配 | 原生支持 |
2.2 开发语言与风格
| Qt Widgets | Qt Quick | |
|---|---|---|
| 主要语言 | C++ | QML(+ 少量 JavaScript) |
| 编程范式 | 命令式 | 声明式 |
| UI 与逻辑 | 混合在 C++ 中 | UI(QML)与逻辑(C++)分离 |
| 学习曲线 | 需要扎实 C++ 基础 | QML 上手较快 |
2.3 功能特性
| Qt Widgets | Qt Quick | |
|---|---|---|
| 动画系统 | 基础 | 丰富,内置多种动画类型 |
| 触控支持 | 有限 | 原生支持多点触控 |
| 自定义样式 | 繁琐 | 灵活,QSS / 属性直接控制 |
| 复杂表格/树形控件 | 成熟完善 | 相对较弱(但持续改进) |
| 无障碍访问 | 完善 | 仍在完善中 |
| Qt Designer 支持 | 完整拖拽设计 | Qt Design Studio |
三、适用场景
应该选 Qt Widgets 的情况
1. 需要与操作系统原生外观高度一致
企业内部工具、行政软件、开发者工具等,用户期望看到"原生"的 Windows 或 macOS 风格界面。Widgets 无需任何配置就能做到这一点。
2. 大量复杂的数据展示
需要大型表格、树形结构、可编辑数据网格的应用(如 IDE、数据库管理工具、ERP 系统),Widgets 的 Model/View 框架非常成熟。
3. 团队有深厚的 C++ 背景
已有大量 C++ 代码库,需要与现有代码深度集成的项目。
4. 典型应用举例
- 桌面 IDE / 代码编辑器
- 企业 ERP / CRM 系统
- 科学计算工具
- 数据库管理软件
应该选 Qt Quick 的情况
1. 需要自定义视觉风格
品牌化的产品 UI、游戏界面、仪表盘等,不希望受系统主题限制,需要完全掌控每一个像素的外观。
2. 流畅动画和过渡效果
Qt Quick 的动画系统基于 GPU 渲染,天然流畅。做炫酷的 UI 过渡、数据可视化动效,Qt Quick 远胜 Widgets。
3. 触控设备 / 移动端
Android、iOS 应用,或带触摸屏的嵌入式设备,Qt Quick 对多点触控的支持比 Widgets 完善得多。
4. UI 与逻辑需要分工协作
设计师用 Qt Design Studio 做 QML 界面,开发者用 C++ 写后端逻辑,两者通过 QML/C++ 集成机制连接。这种分工在 Qt Quick 下非常自然。
5. 典型应用举例
- 汽车中控 / 仪表盘
- 智能家居控制面板
- 嵌入式设备 HMI
- 移动端应用
- 多媒体播放器
- 数据可视化大屏
四、动手对比:同一个 UI,两种写法
用一个包含标签、输入框和按钮的简单表单,直观感受两者的差异。
Qt Widgets 写法(C++)
// mainwindow.h
#include <QMainWindow>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
private slots:
void onSubmit();
private:
QLabel *m_label;
QLineEdit *m_input;
QPushButton *m_button;
};
// mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
QWidget *central = new QWidget(this);
QVBoxLayout *layout = new QVBoxLayout(central);
m_label = new QLabel("请输入名字:", this);
m_input = new QLineEdit(this);
m_button = new QPushButton("提交", this);
layout->addWidget(m_label);
layout->addWidget(m_input);
layout->addWidget(m_button);
setCentralWidget(central);
resize(320, 160);
connect(m_button, &QPushButton::clicked, this, &MainWindow::onSubmit);
}
void MainWindow::onSubmit()
{
m_label->setText("你好," + m_input->text() + "!");
}
Qt Quick 写法(QML)
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
ApplicationWindow {
width: 320
height: 160
visible: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 16
spacing: 8
Label {
id: greetLabel
text: "请输入名字:"
}
TextField {
id: nameInput
Layout.fillWidth: true
placeholderText: "名字"
}
Button {
text: "提交"
onClicked: greetLabel.text = "你好," + nameInput.text + "!"
}
}
}
直观感受:
- Widgets 版本:约 40 行 C++ 代码,需要手动
new控件、设置布局、连接信号 - Qt Quick 版本:约 25 行 QML,声明式描述结构,逻辑内联在
onClicked里
功能完全相同,但 QML 版本更简洁、更直观地表达了"界面是什么样的"。
五、可以混用吗?
可以,Qt 提供了两种方式将 Qt Quick 内容嵌入 Widgets 应用:
方式一:QQuickWidget
在 Widgets 窗口中嵌入一个 QML 场景:
#include <QQuickWidget>
QQuickWidget *qmlView = new QQuickWidget(this);
qmlView->setSource(QUrl("qrc:/MyComponent.qml"));
qmlView->setResizeMode(QQuickWidget::SizeRootObjectToView);
layout->addWidget(qmlView);
方式二:QQuickView
将整个 QML 场景显示为独立窗口,适合渐进式迁移:
#include <QQuickView>
QQuickView *view = new QQuickView();
view->setSource(QUrl("qrc:/Main.qml"));
view->show();
混用的典型场景: 现有 Widgets 应用想引入一个炫酷的数据可视化面板或动画组件,不需要重写整个应用,只在需要的地方嵌入 Qt Quick。
六、决策流程图
用以下问题快速判断你的项目应该选哪个:
需要触控 / 移动端支持?
├── 是 → Qt Quick
└── 否 ↓
需要完全自定义视觉风格 / 复杂动画?
├── 是 → Qt Quick
└── 否 ↓
主要是数据密集型桌面工具(大表格、树形结构)?
├── 是 → Qt Widgets
└── 否 ↓
团队只有 C++ 经验,没有时间学 QML?
├── 是 → Qt Widgets
└── 否 → Qt Quick(现代项目的默认选择)
七、对于本系列的学习者
你的学习目标包含桌面、嵌入式、移动端和 UI 动画,Qt Quick 是主线:
- 移动端(Android / iOS):Qt Quick
- 嵌入式 HMI / MCU:Qt Quick / Qt for MCUs
- UI 动画:Qt Quick 的动画系统
- 桌面应用:Qt Quick 也完全胜任,复杂数据工具再考虑 Widgets
Qt Widgets 作为补充知识了解即可,在本系列的后期阶段(第四阶段)会专项涉及。
总结
| 维度 | Qt Widgets | Qt Quick |
|---|---|---|
| 渲染 | 操作系统原生 | Qt GPU 渲染引擎 |
| 语言 | C++ | QML + JavaScript |
| 动画 | 有限 | 流畅,GPU 加速 |
| 触控 | 有限 | 原生支持 |
| 自定义外观 | 繁琐 | 灵活 |
| 数据表格 | 成熟完善 | 持续改进 |
| 适合场景 | 桌面工具、企业软件 | 移动端、嵌入式、现代 UI |
| 学习曲线 | 需要 C++ 基础 | QML 上手较快 |
一句话总结: 做现代 UI、触控设备、嵌入式 HMI 选 Qt Quick;做传统桌面工具、数据密集型企业软件选 Qt Widgets;两者也可以混用。