Qt Quick vs Qt Widgets如何选择适合你的 UI 技术路线(五)

16 阅读6分钟

适合人群: 了解 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 WidgetsQt Quick
渲染引擎操作系统原生控件Qt 自有 GPU 渲染引擎
外观跟随系统主题完全自定义
动画性能有限,复杂动画吃力流畅,GPU 加速
高 DPI 支持需要手动适配原生支持

2.2 开发语言与风格

Qt WidgetsQt Quick
主要语言C++QML(+ 少量 JavaScript)
编程范式命令式声明式
UI 与逻辑混合在 C++ 中UI(QML)与逻辑(C++)分离
学习曲线需要扎实 C++ 基础QML 上手较快

2.3 功能特性

Qt WidgetsQt 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 WidgetsQt Quick
渲染操作系统原生Qt GPU 渲染引擎
语言C++QML + JavaScript
动画有限流畅,GPU 加速
触控有限原生支持
自定义外观繁琐灵活
数据表格成熟完善持续改进
适合场景桌面工具、企业软件移动端、嵌入式、现代 UI
学习曲线需要 C++ 基础QML 上手较快

一句话总结: 做现代 UI、触控设备、嵌入式 HMI 选 Qt Quick;做传统桌面工具、数据密集型企业软件选 Qt Widgets;两者也可以混用。