2. Qt Quick基础

Qt Quick 是 Qt 面向现代 UI 的声明式框架,QML 是它的描述语言。与传统的 QWidget 命令式构建界面不同,QML 用“对象树 + 属性”的方式描述界面:你声明有哪些元素、它们长什么样、彼此如何关联,运行时由 Qt Quick 引擎负责渲染与更新。理解 QML 语法、基础可视元素以及属性绑定机制,是后续多屏交互工程的地基。

一、QML 语法:对象、属性与层级

QML 文件本质上是一棵对象树。每个元素是一个对象,对象用大括号声明属性,属性用 属性名: 值 的形式赋值。元素之间的父子关系既决定渲染层级,也决定坐标系的相对关系。

import QtQuick 2.15

Rectangle {
    id: root
    width: 320; height: 200
    color: "#eaf4ff"

    Text {
        id: title
        anchors.centerIn: parent
        text: "多屏交互面板"
        font.pixelSize: 20
        color: "#1b4f8a"
    }
}

要点有三:id 是对象在文件内的唯一引用名,用于跨元素访问;属性赋值既可以是常量,也可以是表达式;父子关系通过嵌套或 parent 属性建立。子元素的坐标默认相对父元素,因此移动父元素会带动整棵子树。

二、基础可视元素:Item、Rectangle、Text、Image

Item 是所有可视元素的基类,本身不绘制任何内容,但提供位置、尺寸、锚点、变换、透明度、层级等通用能力。它常被用作容器或逻辑分组节点。

Rectangle 在 Item 基础上增加了填充色、边框、圆角,是最常用的背景与卡片元素。Text 负责文本显示,支持字号、颜色、换行、省略与对齐。Image 负责位图显示,通过 source 指定资源,fillMode 控制缩放策略,asynchronous 可避免大图阻塞界面。

元素核心用途常用属性
Item容器、分组、逻辑节点x、y、width、height、anchors、visible、opacity、z
Rectangle背景、卡片、分隔、色块color、border.color、border.width、radius
Text标题、标签、状态文本text、font.pixelSize、color、wrapMode、elide
Image图标、图片、缩略图source、fillMode、sourceSize、asynchronous

三、属性绑定机制:QML 的灵魂

属性绑定是 QML 区别于普通 UI 框架的关键。当属性值写成表达式时,QML 会记录该表达式依赖了哪些属性;一旦依赖项变化,表达式自动重新求值并更新目标属性。这种“依赖追踪 + 自动重算”让界面状态与数据保持同步,无需手写刷新逻辑。

Rectangle {
    id: card
    width: 240; height: 120
    color: "#ffffff"

    Rectangle {
        id: bar
        width: card.width * 0.6      // 绑定:随 card.width 变化
        height: 8
        color: "#2f9e6e"
        anchors.bottom: parent.bottom
    }

    Text {
        text: "宽度:" + bar.width    // 绑定:随 bar.width 变化
    }
}

绑定可以是简单引用,也可以是函数调用、条件表达式或字符串拼接。需要注意:一旦对已绑定的属性再次用命令式赋值,绑定会被破坏。例如先写 width: parent.width / 2,之后又执行 bar.width = 100,绑定即失效,后续父宽度变化不再影响它。若确实需要动态切换,应使用 Qt.binding() 重新建立绑定。

调试绑定问题时,可临时在表达式中加入 console.log(),观察依赖属性变化时表达式是否被重新求值,从而判断绑定是否仍然有效。

四、锚点布局与多屏场景的关联

锚点(anchors)是 QML 中最常用的相对布局方式,通过 anchors.fill、anchors.centerIn、anchors.left/right/top/bottom 等把元素与父元素或兄弟元素对齐。锚点本身也是绑定:父元素尺寸变化时,被锚定的元素会自动跟随。

在多屏交互工程中,这一特性尤为重要。不同屏幕的分辨率、DPI、宽高比可能不同,若用固定像素写死布局,跨屏时极易错位。更稳妥的做法是:外层用 Item 或 Rectangle 作为屏幕根容器,内部元素通过锚点和比例绑定自适应,再结合 Screen 提供的屏幕信息做差异化处理。

QML 对象树与属性绑定关系 Rectangle (root) width / height / color Rectangle (bar) width: root.width * 0.6 Text (title) text: "宽度:" + bar.width Image (icon) source / fillMode 父子 父子 父子 绑定 绑定规则 1. 表达式依赖的属性变化 → 目标属性自动重算 2. 命令式赋值会破坏已有绑定,需用 Qt.binding() 恢复 3. 锚点本质是绑定,父尺寸变化时子元素自动跟随

五、案例:多屏状态卡片

假设要做一个显示“屏幕连接状态”的卡片,卡片宽度随窗口变化,状态色随连接状态变化,文本随状态更新。用绑定可以一次写完,无需手动刷新:

Rectangle {
    id: statusCard
    width: parent.width * 0.9
    height: 90
    radius: 10
    color: connected ? "#e8f7ee" : "#fdecec"
    border.color: connected ? "#2f9e6e" : "#d9534f"
    border.width: 2

    property bool connected: true

    Text {
        anchors.centerIn: parent
        text: connected ? "屏幕已连接" : "屏幕未连接"
        color: connected ? "#1f7a4d" : "#a33"
        font.pixelSize: 18
    }
}

这里 connected 是自定义属性,改变它即可同时驱动背景色、边框色和文本内容,这正是绑定的价值:一处状态变化,多处视图同步。

六、常见误区与复盘

  • 用命令式赋值覆盖绑定:在 JavaScript 函数里写 rect.width = 200,会切断原有绑定,后续父宽度变化不再生效。
  • 在绑定中做重计算:绑定表达式应尽量轻量,避免在表达式中执行复杂循环或频繁 I/O,否则每次依赖变化都会带来性能开销。
  • 锚点与绝对坐标混用:同一元素既设 anchors.fill 又设 x/y,容易产生冲突或警告,应统一布局策略。
  • 忽略 Image 的加载状态:大图未设置 asynchronous 或 sourceSize 时,可能造成首屏卡顿,多屏场景下更明显。
绑定是“声明关系”,不是“一次性赋值”。当你发现某个属性不再随数据变化时,第一反应应是检查它是否被命令式赋值破坏,而不是怀疑数据源。

掌握 QML 语法、四类基础元素与属性绑定机制后,你就具备了用声明式方式描述多屏界面的能力。后续的布局、状态机、动画与多屏协同,都建立在这套“对象树 + 绑定”的模型之上。