Атрибуты объектов QML

Добавлено 10 мая 2022 в 06:19

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

Атрибуты в объявлениях объектов

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

Набор типов атрибутов объектного типа QML следующий:

  • атрибут id
  • атрибуты свойств
  • атрибуты сигналов
  • атрибуты обработчиков сигнала
  • атрибуты методов
  • прикрепленные свойства и прикрепленные атрибуты обработчиков сигналов
  • атрибуты перечислений

Эти атрибуты подробно обсуждаются ниже.

Атрибут id

Каждый тип объекта QML имеет ровно один атрибут id. Этот атрибут предоставляется самим языком и не может быть переопределен разработчиком или каким-либо типом объекта QML.

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

Ниже представлены объект TextInput и объект Text. Значение id объекта TextInput установлено на «myTextInput». Объект Text устанавливает для своего свойства text то же значение, что и свойство text объекта TextInput, ссылаясь на myTextInput.text. Теперь оба элемента будут отображать один и тот же текст:

import QtQuick 2.0

Column {
    width: 200; height: 200

    TextInput { id: myTextInput; text: "Hello World" }

    Text { text: myTextInput.text }
}

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

После создания экземпляра объекта значение его атрибута id изменить нельзя. Хотя он может выглядеть как обычное свойство, атрибут id не является обычным атрибутом свойства, и к нему применяется особая семантика; например, в приведенном выше примере невозможно получить доступ к myTextInput.id.

Атрибуты свойств

Свойство (property) – это атрибут объекта, которому можно присвоить статическое значение или привязать к динамическому выражению. Значение property может быть прочитано другими объектами. Как правило, оно также может быть изменено другим объектом, если конкретный тип QML явно не запрещает это для определенного свойства.

Определение атрибутов свойств

Свойство может быть определено для типа в C++ путем регистрации Q_PROPERTY класса, который затем регистрируется в системе типов QML. В качестве альтернативы пользовательское свойство типа объекта может быть определено в объявлении объекта в документе QML со следующим синтаксисом:

[default] [required] [readonly] property <propertyType> <propertyName>

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

Имена свойств должны начинаться со строчной буквы и могут содержать только буквы, цифры и символы подчеркивания. Зарезервированные слова JavaScript не являются допустимыми именами свойств. Ключевые слова default, required и readonly являются необязательными и изменяют семантику объявляемого свойства. Дополнительную информацию об их значении смотрите в следующих разделах о свойствах по умолчанию, обязательных свойствах и свойствах только для чтения.

Объявление пользовательского свойства неявным образом создает сигнал изменения значения для этого свойства, а также связанный с ним обработчик сигнала с именем on<PropertyName>Changed, где <PropertyName> – это имя свойства с заглавной первой буквой.

Например, следующее объявление объекта определяет новый тип, производный от базового типа Rectangle. У него есть два новых свойства, причем для одного из этих новых свойств реализован обработчик сигнала:

Rectangle {
    property color previousColor
    property color nextColor
    onNextColorChanged: console.log("The next color will be: " + nextColor.toString())
}
Допустимые типы в определениях пользовательских свойств

В качестве пользовательских типов свойств может использоваться любой из базовых типов QML, кроме типа перечисления. Например, это всё допустимые объявления свойств:

Item {
    property int someNumber
    property string someString
    property url someUrl
}

(Значения перечисления – это просто целочисленные значения, и вместо этого на них можно ссылаться с типом int.)

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

Обратите внимание, что базовый тип var – это обобщенный заполнитель типа, который может содержать значения любого типа, включая списки и объекты:

property var someNumber: 1.5
property var someString: "abc"
property var someBool: true
property var someList: [1, 2, "three", "four"]
property var someObject: Rectangle { width: 100; height: 100; color: "red" }

Кроме того, в качестве типа свойства можно использовать любой тип объекта QML. Например:

property Item someItem
property Rectangle someRectangle

Это относится и к пользовательским типам QML. Если тип QML был определен в файле с именем ColorfulButton.qml (в каталоге, который затем был импортирован клиентом), то свойство типа ColorfulButton также будет допустимым.

Присваивание значений атрибутам свойств

Значение свойства экземпляра объекта может быть указано двумя разными способами:

  • присвоение значения при инициализации;
  • императивное присвоение значения.

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

Присвоение значения при инициализации

Синтаксис для присвоения значения свойству при инициализации:

<propertyName> : <value>

Присвоение значения при инициализации может быть объединено с определением свойства в объявлении объекта. В этом случае синтаксис определения свойства становится следующим:

[default] property <propertyType> <propertyName> : <value>

Ниже приведен пример инициализации значения свойства:

импортировать QtQuick 2.0

import QtQuick 2.0

Rectangle {
    color: "red"
    property color nextColor: "blue" // комбинированное объявление свойства и инициализация
}
Императивное присвоение значения

Императивное присвоение значения – это когда значение свойства (статическое значение или выражение привязки) присваивается свойству из императивного кода JavaScript. Синтаксис императивного присваивания значения – это просто оператор присваивания JavaScript, как показано ниже:

[<objectId>.]<propertyName> = value

Ниже приведен пример императивного присвоения значения:

import QtQuick 2.0

Rectangle {
    id: rect
    Component.onCompleted: {
        rect.color = "red"
    }
}

Статические значения и значения выражений привязки

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

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

Вот пример, показывающий, как оба типа значений присваиваются свойствам:

import QtQuick 2.0

Rectangle {
    // присваивания статических значений при инициализации
    width: 400
    height: 200

    Rectangle {
        // присваивания значений выражений привязки при инициализации
        width: parent.width / 2
        height: parent.height
    }
}

Примечание: Чтобы императивно присвоить выражение привязки, выражение привязки должно содержаться в функции, которая передается в Qt.binding(), а затем значение, возвращаемое Qt.binding(), должно быть присвоено свойству. И, напротив, Qt.binding() нельзя использовать при присваивании выражения привязки при инициализации. Дополнительную информацию смотрите в разделе «Связывание свойств».

Типобезопасность

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

Например, если свойство является типа real, и если вы попытаетесь присвоить ему строку, вы получите ошибку:

property int volume: "four" // выдает ошибку; объект свойства не будет загружен

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

Некоторые типы свойств не имеют естественного представления значений, и для этих типов свойств механизм QML автоматически выполняет преобразование строки в типизированное значение. Так, например, хотя свойства типа color хранят цвета, а не строки, вы можете присвоить строку "red" свойству цвета без сообщения об ошибке.

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

Особые типы свойств

Атрибуты свойств списка объектов

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

[ <item 1>, <item 2>, ... ]

Например, тип Item имеет свойство states, которое используется для хранения списка объектов типа State. В приведенном ниже коде значение этого свойства инициализируется списком из трех объектов State:

import QtQuick 2.0

Item {
    states: [
        State { name: "loading" },
        State { name: "running" },
        State { name: "stopped" }
    ]
}

Если список содержит один элемент, квадратные скобки можно опустить:

import QtQuick 2.0

Item {
    states: State { name: "running" }
}

Свойство типа list может быть указано в объявлении объекта со следующим синтаксисом:

[default] property list<<objectType>> propertyName

и, как и другие объявления свойств, инициализация свойства может быть объединена с объявлением свойства со следующим синтаксисом:

[default] property list<<objectType>> propertyName: <value>

Ниже приведен пример объявления свойства списка:

import QtQuick 2.0

Rectangle {
    // объявление без инициализации
    property list<Rectangle> siblingRects

    // объявление с инициализацией
    property list<Rectangle> childRects: [
        Rectangle { color: "red" },
        Rectangle { color: "blue"}
    ]
}

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

Сгруппированные свойства

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

Например, тип Text имеет сгруппированное свойство font. Ниже первый объект Text инициализирует свои значения шрифта с помощью записи через точку, а второй использует групповую нотацию:

Text {
    // запись через точку
    font.pixelSize: 12
    font.b: true
}

Text {
    // сгруппированная запись
    font { pixelSize: 12; b: true }
}

Типы сгруппированных свойств – это базовые типы, которые имеют подсвойства. Некоторые из этих базовых типов предоставляются языком QML, в то время как другие могут использоваться только в том случае, если импортирован модуль Qt Quick. Дополнительную информацию смотрите в разделе о базовых типах QML.

Псевдонимы свойств

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

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

[default] property alias <name>: <alias reference>

В отличие от обычного свойства псевдоним имеет следующие ограничения:

  • Он может ссылаться только на объект или свойство объекта, которые находятся в области видимости типа, в котором объявлен псевдоним.
  • Он не может содержать произвольные выражения JavaScript.
  • Он не может ссылаться на объекты, объявленные вне области видимости своего типа.
  • Ссылка на псевдоним (alias reference) обязательна, в отличие от необязательного значения по умолчанию для обычного свойства; ссылка на псевдоним должна быть предоставлена ​​при первом объявлении псевдонима.
  • Он не может ссылаться на прикрепленные свойства.
  • Он не может ссылаться на свойства внутри иерархии с глубиной 3 или выше. Следующий код не будет работать:
property alias color: myItem.myRect.border.color

Item {
    id: myItem
    property Rectangle myRect
}

Однако псевдонимы для свойств глубиной до двух уровней будут работать.

property alias color: rectangle.border.color

Rectangle {
    id: rectangle
}

Например, ниже показан тип Button с псевдонимом свойства buttonText, который связано с текстовым объектом дочернего элемента Text:

// Button.qml
import QtQuick 2.0

Rectangle {
    property alias buttonText: textItem.text

    width: 100; height: 30; color: "yellow"

    Text { id: textItem }
}

Следующий код создаст кнопку с определенной текстовой строкой для дочернего объекта Text:

Button { buttonText: "Click Me" }

Здесь изменение buttonText напрямую изменяет значение textItem.text; оно не изменяет какое-либо другое значение, которое затем обновляет textItem.text. Если бы buttonText не был псевдонимом, изменение его значения фактически вообще не изменило бы отображаемый текст, поскольку привязки свойств не являются двунаправленными: значение buttonText изменилось бы, если бы был изменен textItem.text, но не наоборот.

Соображения относительно псевдонимов свойств

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

property alias widgetLabel: label

//выдаст ошибку
//widgetLabel.text: "Initial text"

//выдаст ошибку
//property alias widgetLabelText: widgetLabel.text

Component.onCompleted: widgetLabel.text = "Alias completed Initialization"

Однако при импорте объектного типа QML с псевдонимом свойства в корневой объект это свойство отображается как обычное свойство Qt и, следовательно, может использоваться в ссылках псевдонима.

Свойство псевдонима может иметь то же имя, что и существующее свойство, фактически перезаписывая существующее свойство. Например, следующий тип QML имеет свойство псевдонима color, названное так же, как встроенное свойство Rectangle::color:

Rectangle {
    id: coloredrectangle
    property alias color: bluerectangle.color
    color: "red"

    Rectangle {
        id: bluerectangle
        color: "#1234ff"
    }

    Component.onCompleted: {
        console.log (coloredrectangle.color)    //печатает "#1234ff"
        setInternalColor()
        console.log (coloredrectangle.color)    //печатает "#111111"
        coloredrectangle.color = "#884646"
        console.log (coloredrectangle.color)    //печатает #884646
    }

    //внутренняя функция, которая имеет доступ к внутренним свойствам
    function setInternalColor() {
        color = "#111111"
    }
}

Любой объект, который использует этот тип и ссылается на свое свойство color, будет ссылаться на псевдоним, а не на обычное свойство Rectangle::color. Однако внутри прямоугольник может правильно установить свое свойство color и ссылаться на реальное определенное свойство, а не на псевдоним.

Псевдонимы свойств и типы

Псевдонимы свойств не могут иметь явных спецификаций типа. Тип псевдонима свойства – это объявленный тип свойства или объекта, на который он ссылается. Поэтому, если вы, ссылаясь через id, создаете псевдоним для объекта с дополнительными свойствами, объявленными внутри него, эти дополнительные свойства не будут доступны через псевдоним:

// MyItem.qml
Item {
    property alias inner: innerItem

    Item {
        id: innerItem
        property int extraProperty
    }
}

Вы не можете инициализировать inner.extraProperty снаружи этого компонента, так как inner – это просто Item:

// main.qml
MyItem {
    inner.extraProperty: 5 // ошибка
}

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

// MainItem.qml
Item {
    // Теперь вы можете получить доступ к inner.extraProperty,
    // так как inner теперь является ExtraItem
    property alias inner: innerItem

    ExtraItem {
        id: innerItem
    }
}

// ExtraItem.qml
Item {
    property int extraProperty
}

Свойства по умолчанию

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

Объявление свойства с необязательным ключевым словом default помечает его как свойство по умолчанию. Например, предположим, что есть файл MyLabel.qml со свойством по умолчанию someText:

// MyLabel.qml
import QtQuick 2.0

Text {
    default property var someText

    text: "Hello, " + someText.text
}

Значение someText может быть присвоено в определении объекта MyLabel, например:

MyLabel {
    Text { text: "world!" }
}

Это имеет точно такой же эффект, как и следующий код:

MyLabel {
    someText: Text { text: "world!" }
}

Однако, поскольку свойство someText помечено как свойство по умолчанию, нет необходимости явно назначать объект Text этому свойству.

Вы заметите, что дочерние объекты могут быть добавлены к любому типу на основе Item без явного добавления их к свойству children. Это связано с тем, что свойством по умолчанию элемента Item является его свойство data, и любые элементы, добавленные в этот список для Item, автоматически добавляются в список его дочерних элементов.

Свойства по умолчанию могут быть полезны для переназначения дочерних элементов элемента. Посмотрите пример TabWidget, в котором используется свойство по умолчанию для автоматического переназначения дочерних элементов TabWidget в качестве дочерних элементов внутреннего ListView. Смотрите также Расширение QML.

Обязательные свойства

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

required property <propertyType> <propertyName>

Как следует из названия, обязательные свойства должны быть установлены при создании экземпляра объекта. Нарушение этого правила приведет к тому, что приложения QML не запустятся, если это можно обнаружить статически. В случае динамически создаваемых компонентов QML (например, через Qt.createComponent()) нарушение этого правила приводит к предупреждению и возврату значения null.

Существующее свойство можно сделать обязательным с помощью

required <propertyName>

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

// ColorRectangle.qml
Rectangle {
    required color
}

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

Обязательные свойства играют особую роль в коде модель-представление-делегат: если делегат представления имеет обязательные свойства, имена которых совпадают с именами ролей модели представления, то эти свойства будут инициализированы соответствующими значениями модели. Для получения дополнительной информации посмотрите главу «Модель-представление-делегат» книги «Qt 6 QML Book» и QQuickView::setInitialProperties о способах инициализации обязательных свойств из C++.

Свойства только для чтения

Объявление объекта может определять свойство только для чтения с помощью ключевого слова readonly со следующим синтаксисом:

readonly property <propertyType> <propertyName> : <initialValue>

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

Например, код в блоке Component.onCompleted ниже некорректен:

Item {
    readonly property int someNumber: 10

    Component.onCompleted: someNumber = 20  // не работает, вызовет ошибку
}

Примечание. Свойство только для чтения также не может быть свойством по умолчанию.

Объекты модификаторов свойств

Свойства могут иметь связанные с ними объекты модификатора значения свойства. Синтаксис для объявления экземпляра типа модификатора свойства, связанного с конкретным свойством, следующий:

<PropertyModifierTypeName> on <propertyName> {
    // атрибуты экземпляра объекта
}

Это обычно называют синтаксисом «on».

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

Определенные типы модификаторов свойств могут быть применимы только к определенным типам свойств, однако это не обеспечивается языком. Например, тип NumberAnimation, предоставляемый QtQuick, будет анимировать только свойства числового типа (например, int или real). Попытка использовать NumberAnimation с нечисловым свойством не приведет к ошибке, однако нечисловое свойство не будет анимировано. Поведение типа модификатора свойства, связанного с конкретным типом свойства, определяется его реализацией.

Атрибуты сигналов

Сигнал – это уведомление от объекта о том, что произошло какое-то событие: например, изменилось свойство, запустилась или остановилась анимация, загрузилась картинка. Тип MouseArea, например, имеет сигнал clicked, который испускается, когда пользователь кликает внутри области обработки событий мыши.

Объект может быть уведомлен через обработчик сигнала всякий раз, когда испускается конкретный сигнал. Обработчик сигнала объявляется с синтаксисом on<Signal>, где <Signal> – это имя сигнала с заглавной первой буквой. Обработчик сигнала должен быть объявлен в определении объекта, излучающего сигнал, и должен содержать блок кода JavaScript, который будет выполняться при вызове.

Например, приведенный ниже обработчик сигнала onClicked объявлен в определении объекта MouseArea и вызывается при клике по MouseArea, вызывая печать сообщения консоли:

import QtQuick 2.0

Item {
    width: 100; height: 100

    MouseArea {
        anchors.fill: parent
        onClicked: {
            console.log("Click!")
        }
    }
}

Определение атрибутов сигналов

Сигнал может быть определен для типа в C++ путем регистрации Q_SIGNAL класса, который затем регистрируется в системе типов QML. В качестве альтернативы, пользовательский сигнал для типа объекта может быть определен в объявлении объекта в документе QML со следующим синтаксисом:

signal <signalName>[([<type> <parameter name>[, ...]])]

Попытка объявить два сигнала или метода с одинаковыми именами в блоке одного типа является ошибкой. Однако новый сигнал может повторно использовать имя существующего в типе сигнала (это следует делать с осторожностью, так как существующий сигнал может быть скрыт и стать недоступным).

Вот три примера объявлений сигналов:

import QtQuick 2.0

Item {
    signal clicked
    signal hovered()
    signal actionPerformed(string action, var actionResult)
}

Если сигнал не имеет параметров, скобки "()" необязательны. Если используются параметры, типы параметров должны быть объявлены, как для аргументов string и var сигнала actionPerformed выше. Допустимые типы параметров совпадают с перечисленными в разделе «Определение атрибутов свойств» выше на этой странице.

Чтобы выдать сигнал, вызовите его как метод. Любые соответствующие обработчики сигналов будут вызваны при испускании сигнала, и обработчики смогут использовать определенные имена аргументов сигнала для доступа к соответствующим аргументам.

Сигналы об изменении свойств

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

Атрибуты обработчиков сигналов

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

Рассмотрим следующий тип SquareButton, определение которого содержится в файле SquareButton.qml, как показано ниже, с сигналами activated и deactivated:

// SquareButton.qml
Rectangle {
    id: root

    signal activated(real xPosition, real yPosition)
    signal deactivated

    property int side: 100
    width: side; height: side

    MouseArea {
        anchors.fill: parent
        onReleased: root.deactivated()
        onPressed: (mouse)=> root.activated(mouse.x, mouse.y)
    }
}

Эти сигналы могут быть получены любыми объектами SquareButton в другом файле QML в том же каталоге, где реализации обработчиков сигналов предоставлены клиентом:

// myapplication.qml
SquareButton {
    onDeactivated: console.log("Deactivated!")
    onActivated: (xPosition, yPosition)=> console.log("Activated at " + xPosition + "," + yPosition)
}

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

Обработчики сигналов изменения свойств

Обработчики сигналов для сигнала изменения свойства имеют синтаксическую форму on<Property>Changed, где <Property> – это имя свойства с заглавной первой буквой. Например, хотя документация по типу TextInput не документирует сигнал textChanged, этот сигнал неявно доступен благодаря тому факту, что TextInput имеет свойство text, поэтому можно написать обработчик сигнала onTextChanged, который будет вызываться при каждом изменении этого свойства:

import QtQuick 2.0

TextInput {
    text: "Change this!"

    onTextChanged: console.log("Text has changed to:", text)
}

Атрибуты методов

Метод типа объекта – это функция, которую можно вызвать для выполнения какой-либо обработки или инициирования дальнейших событий. Метод может быть связан с сигналом, чтобы он автоматически вызывался всякий раз, когда сигнал испускается. Дополнительные сведения смотрите в разделе «Система сигналов и обработчиков событий».

Определение атрибутов методов

Метод может быть определен для типа в C++ путем пометки функции класса, которая затем регистрируется в системе типов QML, с помощью Q_INVOKABLE или путем регистрации ее как Q_SLOT класса. Кроме того, пользовательский метод можно добавить к объявлению объекта в документе QML со следующим синтаксисом:

function <functionName>([<parameterName>[, ...]]) { <body> }

К типу QML можно добавлять методы для определения автономных повторно используемых блоков кода JavaScript. Эти методы могут быть вызваны либо внутренними, либо внешними объектами.

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

Попытка объявить два метода или сигнала с одинаковыми именами в блоке одного типа является ошибкой. Однако новый метод может повторно использовать имя существующего в типе метода (это следует делать с осторожностью, так как существующий метод может быть скрыт и стать недоступным).

Ниже показан Rectangle с методом calculateHeight(), который вызывается при присвоении значения высоты:

import QtQuick 2.0
Rectangle {
    id: rect

    function calculateHeight() {
        return rect.width / 2;
    }

    width: 100
    height: calculateHeight()
}

Если у метода есть параметры, они доступны по имени внутри метода. В следующем примере при нажатии на MouseArea вызывается метод moveTo(), который затем может ссылаться на полученные параметры newX и newY для изменения положения текста:

import QtQuick 2.0

Item {
    width: 200; height: 200

    MouseArea {
        anchors.fill: parent
        onClicked: (mouse)=> label.moveTo(mouse.x, mouse.y)
    }

    Text {
        id: label

        function moveTo(newX, newY) {
            label.x = newX;
            label.y = newY;
        }

        text: "Move me!"
    }
}

Прикрепленные свойства и прикрепленные обработчики сигналов

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

Реализация типа QML может выбрать создание присоединяемого типа на C++ с определенными свойствами и сигналами. Экземпляры этого типа затем можно создавать и присоединять к определенным объектам во время выполнения, позволяя этим объектам получать доступ к свойствам и сигналам присоединяемого типа. Доступ к ним осуществляется путем префикса свойств и соответствующих обработчиков сигналов с именем присоединяемого типа.

Ссылки на прикрепленные свойства и обработчики имеют следующий синтаксис:

<AttachingType>.<propertyName>
<AttachingType>.on<SignalName>

Например, тип ListView имеет присоединенное свойство ListView.isCurrentItem, доступное для каждого объекта делегата в ListView. Оно может использоваться каждым отдельным объектом делегата, чтобы определить, является ли он текущим выбранным элементом в представлении:

import QtQuick 2.0

ListView {
    width: 240; height: 320
    model: 3
    delegate: Rectangle {
        width: 100; height: 30
        color: ListView.isCurrentItem ? "red" : "yellow"
    }
}

В этом случае имя присоединяемого типаListView, а рассматриваемое свойство – isCurrentItem, поэтому прикрепленное свойство называется ListView.isCurrentItem.

Прикрепленный обработчик сигнала работает таким же образом. Например, прикрепленный обработчик сигнала Component.onCompleted обычно используется для выполнения некоторого кода JavaScript после завершения процесса создания компонента. В приведенном ниже примере после полного создания ListModel автоматически вызывается обработчик сигнала Component.onCompleted для заполнения модели:

import QtQuick 2.0

ListView {
    width: 240; height: 320
    model: ListModel {
        id: listModel
        Component.onCompleted: {
            for (var i = 0; i < 10; i++)
                listModel.append({"Name": "Item " + i})
        }
    }
    delegate: Text { text: index }
}

Поскольку имя присоединяемого типа – Component, и этот тип имеет сигнал completed, присоединенный обработчик сигнала называется Component.onCompleted.

Примечание о доступе к присоединенным свойствам и обработчикам сигналов

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

Например, ниже приведена модифицированная версия предыдущего примера с прикрепленными свойствами. На этот раз делегатом является Item, а цветной прямоугольник Rectangle является дочерним элементом этого элемента:

import QtQuick 2.0

ListView {
    width: 240; height: 320
    model: 3
    delegate: Item {
        width: 100; height: 30

        Rectangle {
            width: 100; height: 30
            color: ListView.isCurrentItem ? "red" : "yellow"    // Неправильно! Не работает.
        }
    }
}

Это не работает правильно, поскольку ListView.isCurrentItem присоединен только к корневому объекту делегата, а не к его дочерним элементам. Поскольку Rectangle является дочерним элементом делегата, а не самим делегатом, он не может получить доступ к присоединенному свойству isCurrentItem как ListView.isCurrentItem. Поэтому вместо этого прямоугольник должен обращаться к isCurrentItem через корневого делегата:

ListView {
    //....
    delegate: Item {
        id: delegateItem
        width: 100; height: 30

        Rectangle {
            width: 100; height: 30
            color: delegateItem.ListView.isCurrentItem ? "red" : "yellow"   // правильно
        }
    }
}

Теперь delegateItem.ListView.isCurrentItem правильно ссылается на прикрепленное свойство isCurrentItem делегата.

Атрибуты перечислений

Перечисления предоставляют фиксированный набор именованных вариантов. Их можно объявить в QML с помощью ключевого слова enum:

// MyText.qml
Text {
    enum TextType {
        Normal,
        Heading
    }
}

Как показано выше, типы перечислений (например, TextType) и значения (например, Normal) должны начинаться с заглавной буквы.

На значения ссылаются через <Type>.<EnumerationType>.<Value> или <Type>.<Value>.

// MyText.qml
Text {
    enum TextType {
        Normal,
        Heading
    }

    property int textType: MyText.TextType.Normal

    font.bold: textType == MyText.TextType.Heading
    font.pixelSize: textType == MyText.TextType.Heading ? 24 : 12
}

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

Возможность объявлять перечисления в QML появилась в Qt 5.10.

Теги

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

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

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