Top.Mail.Ru

Qt. QML. AnchorChanges, State и PropertyChanges.

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

Итак, любой элемент в QML после создания находится в некотором дефолтном состоянии (состоянии по умолчанию). Данному состоянию соответствуют определенные значения свойств и наборы параметров. QML же, в свою очередь, заботливо дает нам механизм для добавления альтернативных возможных состояний объекта, для которых мы можем установить какие-либо другие наборы свойств, либо произвести вызов некого скрипта. Осуществляется все при помощи упомянутого типа State. По традиции - акцент на практических примерах, которые реально дают понимание о том, что и как функционирует:

import QtQuick 2.15
import QtQuick.Window 2.15



Window {
    id: mainWindow
    width: 640
    height: 480
    visible: true
    title: qsTr("QML States Review")
    color: "#303030"

    Rectangle {
        id: mainRectangle
        color: "orange"

        width: 200
        height: 200

        anchors.centerIn: parent

        states: [
            State {
                name: "clickedOnce"
                PropertyChanges {target: mainRectangle; color: "mediumseagreen"}
            },
            State {
                name: "clickedTwice"
                PropertyChanges {target: mainRectangle; color: "lightsteelblue"}
            }
        ]

        MouseArea {
            anchors.fill: parent

            onClicked: {
                switch (mainRectangle.state) {
                    case "":
                        mainRectangle.state = "clickedOnce";
                        break;

                    case "clickedOnce":
                        mainRectangle.state = "clickedTwice";
                        break;

                    case "clickedTwice":
                        mainRectangle.state = "";
                        break;

                    default:
                        mainRectangle.state = "";
                        break;
                }
            }
        }
    }
}

Поэтапно мы сделали следующее... Добавили Rectangle, разместив его по центру окна и задав его цвет по умолчанию - color: "orange".

К этому же компоненту добавляем возможные состояния. Это делается при помощи свойства states, которое представляет из себя набор элементов типа State. В данном случае у нас два элемента, что означает два возможных состояния (помимо дефолтного). И кроме названия состояний закидываем еще PropertyChanges. Данный тип, в свою очередь, определяет изменение того или иного свойства, указанного в качестве target объекта. Соответственно, здесь мы меняем цвет у mainRectangle, чтобы наглядно оценить переход между состояниями.

Ну и непосредственно переход - сделаем так, чтобы состояния менялись по клику мышью на прямоугольник. Один клик - состояние "clickedOnce", еще один клик - "clickedTwice", следующий клик переводит в состояние по умолчанию. Это осуществляется в виде простейшего конечного автомата в MouseArea. Запускаем, проверяем:

Думаю, идея тут абсолютно ясна, так что перейдем ко второй части - использованию AnchorChanges. По большому счету, AnchorChanges по логике использования похож на PropertyChanges, только изменению подвергаются не свойства, а anchors элемента.

И, конечно, пример:

import QtQuick 2.15
import QtQuick.Window 2.15



Window {
    id: mainWindow
    width: 640
    height: 480
    visible: true
    title: qsTr("QML States Review")
    color: "#303030"

    Rectangle {
        id: mainRectangle
        color: "orange"

        width: 200
        height: 200

        anchors.top: parent.top
        anchors.left: parent.left

        states: [
            State {
                name: "clickedOnce"
                PropertyChanges {target: mainRectangle; color: "mediumseagreen"}
                AnchorChanges {target: mainRectangle; anchors.right: parent.right; anchors.left: undefined}
            },
            State {
                name: "clickedTwice"
                PropertyChanges {target: mainRectangle; color: "lightsteelblue"}
                AnchorChanges {target: mainRectangle; anchors.bottom: parent.bottom; anchors.top: undefined}
            }
        ]

        MouseArea {
            anchors.fill: parent

            onClicked: {
                switch (mainRectangle.state) {
                    case "":
                        mainRectangle.state = "clickedOnce";
                        break;

                    case "clickedOnce":
                        mainRectangle.state = "clickedTwice";
                        break;

                    case "clickedTwice":
                        mainRectangle.state = "";
                        break;

                    default:
                        mainRectangle.state = "";
                        break;
                }
            }
        }
    }
}

Изменения заключается лишь в добавлении AnchorChanges к состояниям элемента. Для "clickedOnce":

AnchorChanges {target: mainRectangle; anchors.right: parent.right; anchors.left: undefined}

Изменения надо указывать относительно дефолтного состояния. Здесь по умолчанию Rectangle в левом верхнем углу. Мы изменяем anchors.right и anchors.left, в результате чего он оказывается в правом верхнем углу. Для "clickedTwice":

AnchorChanges {target: mainRectangle; anchors.bottom: parent.bottom; anchors.top: undefined}

И опять же - было "левый верхний", меняем anchors.bottom / anchors.top - получаем левый же, но нижний угол 👌

Может возникнуть вполне резонный вопрос, почему не поменять просто напрямую, допустим:

function changeAnchors() {
	anchors.right = parent.right;
	anchors.left = undefined;
}

И здесь вступает в силу очередность выполнения инструкций. В данном случае сначала(!) будет изменен anchors.right (при этом anchors.left сохранит исходное значение), что приведет к тому, что элемент растянется на всю ширину. Соответственно, последующее изменение anchors.left = undefined уже ситуации не исправит и вообще ничего не изменит. Этой проблемы помог бы избежать такой вариант:

function changeAnchors() {
	anchors.left = undefined;
	anchors.right = parent.right;
}

Но для того, чтобы в каждом возможном случае не продумывать всю очередность и потенциальные трудности, лучше использовать изначально AnchorChanges, который самостоятельно разруливает данные нюансы.

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

Подписаться
Уведомление о
guest
0 комментариев
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x