【Qt6 QML Book 基础】11:状态和过渡(附完整可运行代码)

引言

在 Qt6 的 QML 编程中,状态(States)和转换(Transitions)是两个强大的概念,它们可以帮助开发者轻松地管理用户界面的不同状态,并为状态之间的切换添加动画效果,从而提升用户体验。本文将详细介绍 QML 中状态和转换的使用方法,并通过一个交通信号灯的实例来演示如何在实际项目中应用这些概念。

一、运行效果图

运行上述代码后,你将看到一个模拟的交通信号灯界面。初始状态为 “stop”,上方的红灯亮起,下方的绿灯熄灭。当你点击界面时,信号灯的状态会在 “stop” 和 “go” 之间切换,并且在从 “stop” 到 “go” 的状态切换过程中,会有 2 秒的颜色过渡动画。

二、QML 状态(States)

2.1 状态语法

在 QML 中,你可以使用State元素来定义状态,它需要绑定到任何项目元素的states数组中。一个状态通过状态名称来标识,最简单的形式是由一系列元素的属性更改组成。默认状态由元素的初始属性定义,名称为""(空字符串)。

Item {
    id: root
    states: [
        State {
            name: "go"
            PropertyChanges { ... }
        },
        State {
            name: "stop"
            PropertyChanges { ... }
        }
    ]
}

通过将新的 state 名称分配给定义状态的元素的 state 属性来更改状态。 

2.2 交通信号灯实践

2.2.1 功能分析

我们要实现一个交通信号灯的模拟,它有两个状态:“stop”(停止)和 “go”(通行)。在 “stop” 状态下,上方的红灯亮起,下方的绿灯熄灭;在 “go” 状态下,上方的红灯熄灭,下方的绿灯亮起。我们还需要添加鼠标交互,以便用户可以点击界面来切换信号灯的状态。

例如,上部的 stop 为红色,下部的 go 为绿色。在此示例中,两个光源不应同时发光。让我们看一下状态图。

  1. 当系统打开时,它会自动进入停止模式作为默认状态。停止状态将 light1 更改为红色,light2 更改为黑色 (关闭)。
  2. 外部事件现在可以触发状态切换到 "go" 状态。在 go 状态下,我们将颜色属性从 light1 更改为黑色(关闭),将 light2 更改为绿色,以指示行人现在可以过马路。

2.2.2 代码实现

2.2.2.1 信号灯绘制

我们开始为 2 个灯绘制用户界面。为简单起见,我们使用 2 个矩形,半径设置为宽度的一半(宽度与高度相同,这意味着它是一个正方形)这样可以实现一个圆形。

 // 上方信号灯(默认熄灭状态)
    Rectangle {
        id: light1
        x: 25; y: 15       // 定位坐标
        width: 100; height: width  // 宽高相等实现圆形
        radius: width / 2  // 圆角半径设为宽度一半
        color: root.black  // 初始颜色
        border.color: Qt.lighter(color, 1.1) // 边框亮色描边
    }

    // 下方信号灯(默认熄灭状态)
    Rectangle {
        id: light2
        x: 25; y: 135      // 纵向间距120px
        width: 100; height: width
        radius: width/2
        color: root.black
        border.color: Qt.lighter(color, 1.1)
    }
2.2.2.2 状态变化 

根据状态图中的定义,我们希望有两种状态:一种是"go"状态,另一种是"stop"状态,每种状态都会将交通信号灯的相应颜色更改为红色或绿色。我们将 state 属性设置为 stop,以确保红绿灯的初始状态是 stop 状态。

// 初始状态设置为"stop"
    state: "stop"

    // 状态定义集合
    states: [
        // 停止状态(红灯亮起)
        State {
            name: "stop"  // 状态标识
            // 属性变更:点亮上方红灯
            PropertyChanges { target: light1; color: root.red }
            // 属性变更:熄灭下方绿灯
            PropertyChanges { target: light2; color: root.black }
        },
        // 通行状态(绿灯亮起)
        State {
            name: "go"
            // 属性变更:熄灭上方红灯
            PropertyChanges { target: light1; color: root.black }
            // 属性变更:点亮下方绿灯
            PropertyChanges { target: light2; color: root.green }
        }
    ]
2.2.2.3 点击交互

使用鼠标区域触发状态更改,该区域覆盖整个交通信号灯,并在单击时在执行状态和停止状态之间切换。

// 鼠标交互区域
    MouseArea {
        anchors.fill: parent  // 充满父容器
        // 点击切换状态(stop <-> go)
        onClicked: parent.state = (parent.state === "stop" ? "go" : "stop")
    }

三、QML 过渡

上面我们已经能够成功地改变交通灯的状态。为了使 UI 更具吸引力和自然性,我们应该添加一些带有动画效果的过渡,状态更改可以触发过渡效果。

3.1 过渡语法

可以为每个项目添加一系列转换。转换由状态更改触发。

可以使用from:to:属性来定义特定转换可以应用于哪些状态更改。这两个属性就像一个过滤器:当过滤器为真时,转换将被应用。还可以使用通配符 “*”,表示 “任何状态”。

例如,from: "*"; to: "*" 表示 “从任何状态到任何其他状态”,并且是 from 和 to 的默认值。这意味着 transition 将应用于每个 state switch。

3.2信号灯状态的过渡

对于交通信号灯的实践,我们想在将状态从 “go” 切换到 “stop” 时对颜色变化进行动画处理。对于另一个反向状态更改(“stop” 到 “go”),我们希望保持即时颜色更改,并且不应用过渡。

这里我们使用 from 和 to 属性来限制过渡,以仅过滤从 “go” 到 “stop” 的状态变化。在过渡中,我们为每个光源添加两个颜色动画,这些动画将对状态描述中定义的属性更改进行动画处理。

// 状态过渡动画配置
    transitions: [
        Transition {
            from: "stop"; to: "go"  // 指定状态切换方向
            // 通用写法:from: "*"; to: "*"(适用于所有状态切换)

            // 上方信号灯颜色过渡动画
            ColorAnimation {
                target: light1     // 作用目标
                properties: "color" // 动画属性
                duration: 2000     // 2秒过渡时间
            }
            // 下方信号灯颜色过渡动画
            ColorAnimation {
                target: light2
                properties: "color"
                duration: 2000
            }
        }
    ]

四、性能优化

4.1 状态管理原则

  • 单一职责:每个状态专注于一组相关属性变更,避免混合无关逻辑;
  • 复用优先:通过继承或混入(Mixin)共享公共状态(如 disabled 状态);
  • 延迟激活:使用 State.onActive 信号延迟执行非必要操作(如网络请求)。

4.2 转换性能优化

  • 减少动画对象:合并同类动画(如同时变更颜色和透明度时使用 ColorAnimation 而非多个动画);
  • 硬件加速:对复杂动画元素设置 layer.enabled: true
  • 避免循环依赖:状态切换逻辑中避免相互触发多个状态,防止动画卡顿。

总结

通过本文的介绍,我们了解了 QML 中状态和转换的基本概念和使用方法。状态可以帮助我们管理用户界面的不同状态,而转换则可以为状态之间的切换添加动画效果,从而提升用户体验。在实际项目中,我们可以根据需要定义更多的状态和转换,以实现更加复杂和生动的用户界面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

binary0010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值