Spec-Zone.ru › Qt

Связывание свойств

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

Связывания свойств — это ключевая функция QML, которая позволяет разработчикам задавать отношения между различными свойствами объектов. Когда значения зависимостей свойства изменяются, свойство автоматически обновляется в соответствии с заданным отношением.

За кулисами движок QML отслеживает зависимости свойства (то есть переменные в выражении связывания). При обнаружении изменения движок QML повторно оценивает выражение связывания и применяет новый результат к свойству.

Обзор

Для создания связывания свойства, свойству присваивается выражение JavaScript, которое вычисляется до желаемого значения. В простейшем случае связывание может быть ссылкой на другое свойство. Рассмотрим следующий пример, где высота синего прямоугольника Rectangle связана с высотой его родителя:

Rectangle {
    width: 200; height: 200

    Rectangle {
        width: 100
        height: parent.height
        color: "blue"
    }
}

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

Связывание может содержать любое допустимое выражение или оператор JavaScript, так как QML использует совместимый с стандартами движок JavaScript. Связывания могут обращаться к свойствам объектов, вызывать методы и использовать встроенные объекты JavaScript, такие как Date и Math. Ниже приведены другие возможные связывания для предыдущего примера:

height: parent.height / 2

height: Math.min(parent.width, parent.height)

height: parent.height > 100 ? parent.height : parent.height/2

height: {
    if (parent.height > 100)
        return parent.height
    else
        return parent.height / 2
}

height: someMethodThatReturnsHeight()

Ниже приведен более сложный пример, включающий больше объектов и типов:

Column {
    id: column
    width: 200
    height: 200

    Rectangle {
        id: topRect
        width: Math.max(bottomRect.width, parent.width/2)
        height: (parent.height / 3) + 10
        color: "yellow"

        TextInput {
            id: myTextInput
            text: "Hello QML!"
        }
    }

    Rectangle {
        id: bottomRect
        width: 100
        height: 50
        color: myTextInput.text.length <= 10 ? "red" : "blue"
    }
}

В предыдущем примере,

  • topRect.width зависит от bottomRect.width и column.width
  • topRect.height зависит от column.height
  • bottomRect.color зависит от myTextInput.text.length

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

Создание связываний свойств из JavaScript

Свойство со связыванием автоматически обновляется по мере необходимости. Однако, если свойству позже присваивается статическое значение из оператора JavaScript, связывание будет удалено.

Например, Rectangle ниже изначально гарантирует, что его height всегда вдвое больше его width. Однако, при нажатии клавиши пробела, текущее значение width*3 будет присвоено height как статическое значение. После этого значение height останется неизменным, даже если width изменится. Присвоение статического значения удаляет связывание.

import QtQuick 2.0

Rectangle {
    width: 100
    height: width * 2

    focus: true
    Keys.onSpacePressed: {
        height = width * 3
    }
}

Если целью является придание прямоугольнику фиксированной высоты и остановка автоматических обновлений, то это не проблема. Однако, если целью является установление нового отношения между width и height, то новое выражение связывания необходимо заключить в функцию Qt.binding():

import QtQuick 2.0

Rectangle {
    width: 100
    height: width * 2

    focus: true
    Keys.onSpacePressed: {
        height = Qt.binding(function() { return width * 3 })
    }
}

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

Отладка перезаписи связываний

Распространённой причиной ошибок в QML-приложениях является случайная перезапись связываний статическими значениями из операторов JavaScript. Для помощи разработчикам в отслеживании проблем такого рода, движок QML может генерировать сообщения всякий раз, когда связывание теряется из-за императивных присвоений.

Для генерации таких сообщений, необходимо включить информационную вывод для категории логирования qt.qml.binding.removal, например, вызвав:

QLoggingCategory::setFilterRules(QStringLiteral("qt.qml.binding.removal.info=true"));

Для получения дополнительной информации об включении вывода из категорий логирования, обратитесь к документации QLoggingCategory.

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

Использование this со связыванием свойств

При создании связывания свойства из JavaScript, ключевое слово this может быть использовано для ссылки на объект, который получает связывание. Это полезно для устранения неоднозначности с именами свойств.

Например, обработчик Component.onCompleted ниже определен в области видимости Item. В этой области видимости width относится к ширине Item, а не ширине Rectangle. Чтобы связать height прямоугольника Rectangle с его собственной width, выражение связывания должно явно ссылаться на this.width (или, альтернативно, rect.width):

Item {
    width: 500
    height: 500

    Rectangle {
        id: rect
        width: 100
        color: "yellow"
    }

    Component.onCompleted: {
        rect.height = Qt.binding(function() { return this.width * 2 })
        console.log("rect.height = " + rect.height) // prints 200, not 1000
    }
}

Примечание: Значение this не определено за пределами связываний свойств. См. Ограничения среды JavaScript для получения подробностей.

См. также Позиционирование с якорями.

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/qtqml-syntax-propertybinding.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API