咖啡机

一个具有基于状态的定制用户界面的 Qt Quick 应用程序。

咖啡机示例概述

此应用程序展示了如何以跨平台、多种屏幕尺寸和响应式的方式实现产品定制的典型用户界面。

选择食谱

咖啡选择

咖啡机应用程序允许您选择咖啡类型,并指示您可以订购多少该类型的咖啡。

咖啡定制

选择一种食谱后,应用程序将显示咖啡混合物中将包含多少比例的

  • 已冲泡咖啡
  • 热水
  • 奶泡

这些可以使用滑块进行修改。

显示冲泡状态

一旦用户确认杯子在机器中,冲泡就开始。

冲泡开始后,应用程序将显示冲泡过程的动画。

咖啡已准备好

冲泡过程结束后,应用程序将显示几秒钟带有所需混合物的咖啡杯,然后返回到起始页面。

它是如何工作的

在此,我们讨论了这些功能的实现方式。

适应屏幕尺寸和方向

应用程序窗口根对象具有高度和宽度的初始值,这些值将被用作桌面平台上的窗口大小。默认的 QWindow::AutomaticVisibility 确保在需要此功能的平台上(如移动平台)将窗口以最大化或全屏显示。

ApplicationWindow {
    visible: true
    width: 1000
    height: 600
    title: qsTr("Coffee")

从那里,ApplicationWindow 的子对象会获取 ApplicationWindow 的大小,以确定它们自己的大小。

该应用程序在整个应用程序页面组件中使用 GridLayout 来轻松适应屏幕方向的变化。

应用程序使用 StackView QML 类型来显示应用程序的不同页面。处理不同页面组件的 StackViewApplicationFlowForm.ui.qml 中实现。

从一个页面导航到下一个页面将在 ApplicationFlow.qml 中触发状态更改,其中所需的属性更改由 PropertyChanges QML 类型处理

states: [
    State {
        name: "Home"
        PropertyChanges {
            target: toolbar
            backButton.opacity: 0
            backButton.enabled: false
            themeButton.opacity: 0
            themeButton.enabled: false
            logo.sourceSize.width: 70
            logo.sourceSize.height: 50
        }

在状态变化期间发生的动画是使用在 StackView 组件内实现的 TransitionPropertyAnimation 来实现的,这些都在 ApplicationFLowForm.ui.qml

实现启动页面

应用程序通过将 Home 页面显示给用户作为 StackView 中的初始项来启动。

StackView {
    id: stack
    anchors.top: parent.top
    anchors.bottom: parent.bottom
    anchors.left: parent.left
    anchors.right: parent.right
    anchors.topMargin: parent.height / 20
    initialItem: Home {
        id: home
        visible: true
        state: applicationFlow.mode
    }
    pushEnter: Transition {
        PropertyAnimation {
            property: "x"
            from: stack.width
            to: 0
            duration: 400
        }
    }

Home 组件通过将 Item 组件作为根对象进行结构化,其中包括状态机和合适的属性别名,然后是 GridLayout。这种类型的结构将在所有应用程序页面组件中使用。

Home 页面显示一个带有 Qt 标志的咖啡杯图片,标题为“咖啡机”,以及在用户可以期待的内容上的一些引人注目的简介和 getStartedButton 按钮。

用户可以通过按下 getStartedButton 前进,按钮 onClicked 函数是在 ApplicationFlow.qml 中实现的。

home.getStartedbutton.onClicked: {
    applicationFlow.state = "Coffee-selection"
    stack.push(choosingCoffee)
}

这将在 ApplicationFlow.qml 中触发状态变化到 "Coffee-selection",并将 choosingCoffee 组件推到 StackView 中的 Home 组件之上。

实现咖啡机选择

在咖啡选择页面 ChoosingCoffee.qml 中显示,此处用户可以看到 4 种不同的咖啡选项可供选择。这些选项以 CoffeeCards 的形式显示,这些卡牌位于 ChoosingCoffee.qml 中的 GridLayout 内。

GridLayout {
    id: cards
    anchors.horizontalCenter: parent.horizontalCenter
    anchors.top: parent.top
    rowSpacing: 20
    columnSpacing: 20
    CoffeeCard {
        id: cappuccino
        coffeeName: "Cappuccino"
        ingredients: "Milk, Espresso, Foam"
        time: 2
        cupsLeft: applicationFlow.cappuccinos
    }
    CoffeeCard {
        id: latte
        coffeeName: "Latte"
        ingredients: "Coffee, Foam"
        time: 3
        cupsLeft: applicationFlow.lattes
    }
    CoffeeCard {
        id: espresso
        coffeeName: "Espresso"
        ingredients: "Milk, Espresso"
        time: 2
        cupsLeft: applicationFlow.espressos
    }
    CoffeeCard {
        id: macchiato
        coffeeName: "Macchiato"
        ingredients: "Milk foam, Espresso"
        time: 4
        cupsLeft: applicationFlow.macchiatos
    }
}

CoffeeCard 的实现位于 CoffeeCard.qml

这些卡牌可以根据 ApplicationWindow 根对象遵循的可用屏幕宽度和高度属性以网格或一行的方式显示。这种状态机将向下传递给 ChoosingCoffee.qml 和此处的 GridLayout

CoffeeCards 在名称、冲泡时间、成分以及当前可用的杯数上有所不同。

在此页上,用户还可以通过按下屏幕右上角的类似小太阳的图标按钮来第一次更改应用程序主题。

function themeButton() {
    if (Colors.currentTheme == Colors.dark) {
        Colors.currentTheme = Colors.light
    } else {
        Colors.currentTheme = Colors.dark
    }
}

该函数将 Colors.qml 中的 currentTheme 属性更改,并通过属性绑定自动更改整个应用程序中的颜色。应用程序中使用的所有颜色都位于 Colors.qml

如果将主题切换到浅色主题,主题更改图标按钮的图标将变为半月的形状。

按下任何咖啡卡将触发在 CoffeeCard.qml 中的 AbstractButton 内的状态变化,这然后将通过 Transition 触发 NumberAnimation

AbstractButton {
    width: parent.width - 2
    height: parent.height - 2
    anchors.horizontalCenter: parent.horizontalCenter
    anchors.verticalCenter: parent.verticalCenter
    id: button
    hoverEnabled: true
    checkable: true
    enabled: (cupsLeft != 0) ? true : false
    transitions: Transition {
        NumberAnimation {
            properties: "scale"
            duration: 50
            easing.type: Easing.InOutQuad
        }
    }

这将缩小所选咖啡卡的尺寸,并将卡的边缘变为绿色,使用户感觉到咖啡已经选中。

每个咖啡卡片 button 属性别名 onClicked 函数绑定到位于 ApplicationFlow.qml 的一个函数。当用户按下任何咖啡卡片时,名称与所选咖啡选项相关的函数将被调用。该函数将 ApplicationFlow.qml 的状态设置为 Settings,向 StackView 推送一个新的组件,并相应地设置成分配置。

实现咖啡设置

在页面中,用户可以通过调整自定义 Slider QML 类型来自定义他们的咖啡选项以匹配他们的个人喜好。滑动条的值更改将影响咖啡杯内部看到的液体水平,这是通过将 Cup.qml 中液体图像的高度绑定到相应滑动条的值来实现的。

滑动条的值将通过 onValueChanged 函数存储到 ApplicationFlow.qml 的属性变量中。

coffeeSlider.onValueChanged: {
    applicationFlow.coffeeAmount = coffeeSlider.value
}

点击“开始”按钮将 ApplicationFlow.qml 的状态更改为“插入”,并显示 Insert.qml

实现插入杯子

在此页面中,用户被指示在开始冲泡过程之前将杯子插入机器。

按下“继续”按钮会将应用移动到 Progress 页面。

实现冲泡咖啡

进度页面显示一个咖啡杯和进度条,它们将以各自的方式实时信号化冲泡过程。

这里的咖啡杯一旦装满,将显示出与用户在 Settings 页面上选择的完全相同的配置,这是通过将 Cup 属性变量绑定到在 ApplicationFlow.qml 中保存的相应值来确保的。

填充咖啡杯的动画由状态引擎 TransitionSmoothedAnimation 执行。

Cup {
    id: cup
    Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
    state: "0"
}

进度条动画使用 Behavior 实现。

Behavior on greenBar.width {
    SmoothedAnimation {
        easing.type: Easing.Linear
        velocity: (contentItem.width / brewTime) * 1000
    }
}

Timer 将负责在冲泡完成后更新应用程序状态。

Timer {
    id: timer
    interval: brewTime
    running: true
    onTriggered: {
        applicationFlow.onFinished()
    }
}
实现咖啡已准备好

已准备好页面显示一个装满了用户选择的配置的咖啡杯,并带有“您的咖啡准备好了”文本和勾选图标。

当显示此页面时,将启动一个 Timer,一旦达到设定的间隔,用户将被引导回 Home.qml

示例项目 @ 代码.qt.io

© 2024 Qt 公司有限公司。包含了其中的文档贡献的版权均为各自所有者所拥有。在此提供的文档是根据自由软件基金会发布的 GNU 自由文档许可证版本 1.3 的条款 许可的。Qt 以及相应的标志是芬兰的 Qt 公司在全球范围内的注册商标。所有其他商标均为其各自所有者的财产。