# Qt 6 简介

# Qt Quick

Qt Quick 是 Qt 6 中使用的用户界面技术的总称。它在 Qt 4 引入,壮大于 Qt 6。Qt 6 是好几项技术的集合:

  • QML - 用于用户界面的标记语言
  • JavaScript - 动态脚本语言
  • Qt C++ - 极致优化且轻量的 c++ 库

与 HTML 类似,QML 是一种标记语言。QML 由标签组成(在 Qt Quick 中被称为类型),包含了一对大括号,形如 Item {}。它是重新设计的,旨在让开发者快速创建更易读的用户界面。用户界面可通过 JavaScript 代码进一步增强。Qt Quick 能方便地通过 Qt C++ 编写的原生功能进行扩展。简而言之,申明式 UI 被称为前端,原生代码被称为后端。这使得你将密集的计算和原生操作从用户界面中分离出来。

在典型项目中,前端由 QML/JavaScript 开发。后端代码由 Qt C++ 开发,负责与系统交互和一些重活。这很自然的划分出了设计工程师和功能开发工程师。一般来说,后端代码由 Qt Test(Qt 单元测试框架)进行测试后,导出给前端工程使用。

# 认识用户界面

让我们利用 Qt Quick 创建一个简单的用户界面,它将展示 QML 语言的好几个知识点。最后的成品是一个有几个扇叶的纸风车。

首先新建一个空的 main.qml 文件。所有的 QML 文件都有后缀 .qml。作为一种标记语言(类似 HTML),一个 QML 文档有且仅有一个根节点。在本例中,根节点是一个 Image 类型的,它的宽高基于指定的背景图:

import QtQuick

Image {
    id: root
    source: "images/background.png"
}

由于 QML 并未限制根节点的类型,本例中我们使用 Image 类型,它的 source 属性被设置为指定背景图。

提示

每种类型都有其属性。例如,图片有属性 widthheight,均存储着像素值。它也有其它属性,例如 source。由于图片类型自动从图片中继承了尺寸,我们无需再手动设置 widthheight 属性。

大部分的标准类型位于 QtQuick 模块中,可在 .qml 文件的开头通过 import 语句导入。

id 是一个特殊的可选属性,它包含了一个标识符,可在文档的其它位置引用其关联的类型。重点: id 属性设置后就无法修改,且无法再运行时设置。本书约定以 root 作为最顶层节点的 id,便于在后续更大的 QML 文档中找到根节点。

用户界面中的前置元素,一根杆和风车是两张独立的图片。

我们想将这根杆相对于背景图水平居中,底部对齐。而风车则置于背景图的正中心。

虽然我们的入门示例只使用了图片类型,后面我们会慢慢的引导你创建由更多不同类型组成的复杂界面。

Image {
    id: root
    ...
    Image {
        id: pole
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottom: parent.bottom
        source: "images/pole.png"
    }

    Image {
        id: wheel
        anchors.centerIn: parent
        source: "images/pinwheel.png"
    }
    ...
}

将风车置于正中,我们需要用到名为 anchor 的复杂属性。锚点允许你指定父元素和其子元素之间的几何关系。例如,anchors.centerIn: parent 会将我置于父元素的中心。左对右,上对下,居中对填充,垂直居中对水平居中。一般来说,多个锚点同时使用时,他们必须互相兼容,例如,将一个元素的左侧和另一个元素的顶部对齐将不会产生任何作用。

风车只需一个简单的锚点。

提示

有时,你想做些微调,例如,将其稍微偏移中心点。这可通过 anchors.horizontalCenterOffsetanchors.verticalCenterOffset 完成。类似的调整属性对其它的标点也是适用的,可通过文档查看完整的锚点属性。

提示

将子类型图片置于根节点(本例中是 Image)下说明了申明式语言的一个重要原则。你所申明的可视外观的层级和分组,会先绘制最顶层(我们的背景图)的层级,然后基于其坐标系,在其上继续绘制子层级。

为了让案例变得更有趣,让我们赋予其一点交互性。当用鼠标点击画面的任一点时旋转风车。

我们使用 MouseArea 类型包裹根节点。

Image {
    id: root
    ...
    MouseArea {
        anchors.fill: parent
        onClicked: wheel.rotation += 90
    }
    ...
}

当用户点击 MouseArea 覆盖的区域时,他会发送一个信号。你可以通过重写 onClicked 函数来连接此信号。当信号被连接后,发送信号就会调用关联的函数。在本例中,当点击事件触发时,idwheel 的元素(本例中为风车图片)会顺时针旋转 90 度。

提示

这项技术对每种信号都有效,它的命名规则是 on + SignalName。同时,所有的属性值变更时,也会发送信号。这些信号的命名规则是:

    `on${property}Changed`

例如,若 width 属性值发生变化,你可以通过 onWidthChanged: print(width) 观察。

现在这个风车会在用户点击时旋转了,但旋转动作是立刻完成的,而不是在一段时间内慢慢转动。可以通过动画来实现平滑转动。动画定义了属性值如何在一段时间内转变成另一个值。要启用动画,需要使用 Animation 类型的 Behavior 属性。Behavior 为属性值的修改定义了一套变化过程。换而言之,无论何时属性值变化,动画就会运行。这只是在 QML 中使用动画的一种方式。

Image {
    id: root
    Image {
        id: wheel
        Behavior on rotation {
            NumberAnimation {
                duration: 250
            }
        }
    }
}

现在,无论何时旋转角度发生变化,它都会通过 NumberAnimation 触发一个 250 毫秒的动画。每次的 90 度旋转将耗时 250 毫秒,这将使得旋转变得流畅。

提示

你不会真的看到这个风车转的模糊。因为它的旋转只修改了角度。(assets 目录中有一个模糊的风车图片,你可以换它试试。)

现在这个风车看起来好多了,且转的更舒心了。我们在也在这个过程中简单的了解了 Qt Quick 编程是如何工作的。