Состояния и переходы в QML

Добавлено 13 марта 2022 в 03:08

Часто компоненты пользовательского интерфейса можно описать с помощью состояний. Состояние определяет набор изменений свойств и может быть вызвано определенным условием.

Кроме того, к этим переключателям состояния может быть присоединен переход, который определяет, как эти изменения должны быть анимированы, или любые дополнительные действия, которые должны быть применены. Действия также могут применяться при входе в состояние.

Состояния

Состояния в QML определяются с помощью элемента State, который необходимо привязать к массиву states любого элемента Item.

Состояние идентифицируется по имени и в своей простейшей форме состоит из последовательности изменений свойств элементов. Состояние по умолчанию определяется начальными свойствами элемента и имеет имя "" (пустая строка).

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

Состояние изменяется путем присвоения нового имени состояния свойству state элемента, в котором определено состояние.

Item {
    id: root
    states: [
        ...
    ]

    Button {
        id: goButton
        ...
        onClicked: root.state = "go"
    }
}

Управляйте состояниями, используя when

Другой способ управления состояниями – использование свойства when элемента State. Свойству when можно присвоить выражение, которое оценивается как true, когда следует применять состояние.

светофор

Например, светофор может иметь два индикатора. Верхний сигнализирует «стоп» красным цветом, а нижний сигнализирует «идти» зеленым цветом. В этом примере оба индикатора не должны гореть одновременно. Давайте посмотрим на диаграмму диаграммы состояний.

диаграмма состояний

Когда система включается, она автоматически переходит в режим «стоп», что является состоянием по умолчанию. В состоянии "stop" индикатор light1 меняется на красный, а ligth2 – на черный (выключена).

Внешнее событие теперь может инициировать переключение состояния в состояние "go". В состоянии «идти» мы меняем свойства цвета light1 на черный (выключена), а light2 на зеленый, чтобы указать, что пешеходы теперь могут переходить дорогу.

Чтобы реализовать этот сценарий, мы начинаем рисовать наш пользовательский интерфейс для двух индикаторов. Для простоты мы используем 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
    width: 100; height: width
    radius: width/2
    color: root.black
    border.color: Qt.lighter(color, 1.1)
}

Как определено в диаграмме состояний, мы хотим иметь два состояния: одно – состояние "go", а другое – состояние "stop", где каждое из них меняет цвет соответствующего индикатора светофора на красный или зеленый. Мы устанавливаем свойство state на 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 }
    }
]

Начальное состояние

Мы могли бы добиться того же эффекта только с состоянием "go" и без явного состояния "stop", установив цвет light1 на красный, а цвет light2 на черный. Начальное состояние "", определенное начальными значениями свойств, будет действовать как состояние "stop".

Использование PropertyChanges { target: light2; color: "black" } в этом примере на самом деле не требуется, так как исходный цвет light2 уже черный. В состоянии необходимо только описать, как свойства должны измениться по сравнению с их состоянием по умолчанию (а не с предыдущим состоянием).

Изменение состояния запускается с помощью области обработки событий мыши, которая покрывает весь светофор и при нажатии переключает состояние между "stop" и "go".

MouseArea {
    anchors.fill: parent
    onClicked: parent.state = (parent.state == "stop"? "go" : "stop")
}
состояния

Теперь мы можем успешно изменить состояние светофора. Чтобы сделать пользовательский интерфейс более привлекательным и естественным, мы должны добавить переходы с анимационными эффектами. Переход может быть вызван изменением состояния.

Использование скриптов

Подобную логику можно создать, используя скрипты вместо состояний QML. Однако QML лучше подходит для описания пользовательских интерфейсов, чем JavaScript. По возможности старайтесь писать декларативный код вместо императивного.

Переходы

К каждому элементу можно добавить ряд переходов. Переход выполняется изменением состояния.

Вы можете определить, к какому изменению состояния можно применить конкретный переход, используя свойства from: и to:. Эти два свойства действуют как фильтр: когда этот фильтр имеет значение true, будет применен переход. Вы также можете использовать подстановочный символ "*", что означает «любое состояние».

Например, from: "*"; to: "*" означает «из любого состояния в любое другое состояние» и является значением по умолчанию для from и to. Это означает, что переход будет применяться к каждому переключению состояния.

В этом примере мы хотели бы анимировать изменение цвета при переключении состояния с "go" на "stop". Для обратного изменения состояния ("stop" на "go") мы хотим сохранить немедленное изменение цвета и не применять переход.

Мы ограничиваем переход свойствами from и to, чтобы отфильтровать изменение состояния только с "go" на "stop". Внутри перехода мы добавляем две анимации цвета для каждого индикатора, которые будут анимировать изменения свойств, определенные в описании состояния.

transitions: [
    Transition {
        from: "stop"; to: "go"
        // from: "*"; to: "*"
        ColorAnimation { target: light1; properties: "color"; duration: 2000 }
        ColorAnimation { target: light2; properties: "color"; duration: 2000 }
    }
]

Вы можете изменить состояние, кликнув на пользовательский интерфейс. Состояние применяется немедленно, и клик изменит состояние во время выполнения перехода. Итак, попробуйте кликнуть на пользовательский интерфейс, когда состояние находится в переходе от "stop" на "go". Вы увидите, что изменения произойдут немедленно.

изменение состояния

Вы можете поэкспериментировать с этим пользовательским интерфейсом, например, уменьшая масштаб неактивного индикатора, чтобы выделить активный индикатор.

Для этого вам нужно будет добавить в состояния еще изменение свойства для масштабирования, а также доработать анимацию для свойства масштабирования в переходе.

Другой вариант – добавить состояние "attention" (внимание), когда индикаторы мигают желтым цветом. Для этого вам нужно будет добавить к переходу последовательную анимацию на одну секунду, ведущую к желтому (свойство анимации to и одна секунда, ведущая к «черному»).

Возможно, вы также захотите изменить кривую плавности, чтобы сделать ее визуально более привлекательной.

Теги

GUI / Графический интерфейс пользователяQMLQtQtQuickАнимацияПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.