Как и в виджетах, в Qt Quick/QML также применяется паттерн View/Model, который состоит из трех компонентов:
Модель: содержит данные и их структуру
Представление: отображает данные
Делегат: определяет, как данные должны отображаться в представлении. Делегат также применяется для сохранения измененных данных обратно в модель
Qt Quick предоставляет ряд встроенных типов представлений:
ListView: располагает данные в виде списка
GridView: располагает данные в виде грида
TableView: располагает данные в виде таблицы
TreeView: располагает данные в виде дерева
PathView: располагает данные, используя геометрические пути (фигуры)
Для работы с представлениями в Qt Quick определен ряд классов моделей, основные из них:
ListModel: определяет данные в виде списка
TableModel: определяет данные в виде таблицы
DelegateModel: объединяет модель и делегат
ObjectModel: определяет набор данных, которые применяются в качестве модели
XmlListModel: использует данные в формате xml
Большинство моделей располагается в пакете " QtQml.Models", однако некоторые модели, например, TableModel, на момент написания текущей статьи имеют экспериментальный статус и поэтому располагаются в пакете "Qt.labs.qmlmodels". Отдельные типы моделей могут располагаться в других пакетах
Для связи представления с моделью класс представления определяет свойство model. Этому свойству передается объект модели. Для управления визуализацией данных модели типы представлений также определяют свойство delegate, которому передается шаблон данных в виде объекта Component или другого совместимомго типа.
В качестве модели для свойства model можно указать следующие данные:
Объект встроенного типа модели (например, ListModel, XmlListModel, ObjectModel и т.д.), который содержит данные
Объект класса C++, который унаследован от абстрактного класса QAbstractItemModel
Массив JavaScript
Число - количество создаваемых элементов
Если свойству model
представления передается число, то оно определяет количество элементов, которые создает делегат. В этом случае также устанавливается свойство
delegate, которое и представляет делегат. В качестве значения ему передается объект Component (или объект иного совместимого типа),
который представляет шаблон элемента представления. Стоит отметить, что число в model ограничено значением 100 000 000.
Создание списка на примере представления ListView:
import QtQuick Window { width: 250 height: 150 visible: true title: "METANIT.COM" ListView { anchors.fill: parent model: 5 delegate: Text { text: "Item " + index } } }
В данном случае создается пять элементов
model: 5
Для создания применяется делегат
delegate: Text { text: "Item " + index }
То есть для каждого элемента создается элемент Text, в котором устанавливается свойство "text". По умолчанию через свойство "index" внутри делегата можно получить индекс создаваемого элемента.
В качестве модели может выступать обычный массив JavaScript:
import QtQuick Window { width: 250 height: 150 visible: true title: "METANIT.COM" ListView { anchors.fill: parent model: ["Tom", "Bob", "Sam"] delegate: Text {text: modelData} } }
Здесь в качестве модели применяется массив из трех строк. Таким образом, для каждого элемента будет выполняться делегат, который создаст по одному элементу Text. Внутри делегата каждый элемент модели можно получить с помощью свойства modelData
Причем массив может представлять более сложные данные - объекты с определенными свойствами. В этом случае также через modelData можно обратиться к свойствам объекта:
import QtQuick Window { width: 250 height: 150 visible: true title: "METANIT.COM" ListView { anchors.fill: parent model: [ {name:"Tom", age:39}, {name:"Bob", age:43}, {name:"Sam", age:28} ] delegate: Text {text: modelData.name + " (" + modelData.age + ")"} } }
В данном случае каждый объект в массиве сожержит два свойства: name и age, значения которых отображаются в элементе Text.
Для различных ситуаций Qt Quick представляет ряд моделей. Например, для создания списка можно использовать модель ListModel:
import QtQuick Window { width: 250 height: 150 visible: true title: "METANIT.COM" ListModel { id: usersModel ListElement { name: "Tom" age: 39 } ListElement { name: "Bob" age: 43 } ListElement { name: "Sam" age: 28 } } ListView { anchors.fill: parent model: usersModel spacing: 5 delegate: Text { text: name + " (" + age + ")" } } }
Модель определяется типом ListModel из пакета "QtQml.Models". Это не единственный тип модели, который мы можем использовать. При необходимости мы можем создавать свои типы моделей. ListModel — это простой контейнер элементов ListElement, каждое из которых содержит роли данных. Содержимое ListModel может быть определено динамически или явно в QML.
Тип ListElement представляет отдельный элемент списка в ListModel. ListItem определяется, как и другие элементы в QML, только вместо свойств содержит
роли (согласно терминологии официальной документации). Например, в примере выше для каждого ListElement определяются две роли - "name" и
"age". Имена ролей должны начинаться со строчной буквы и быть общими для всех элементов в данной модели. Значения должны быть простыми константами: строки, логические значения
(true, false), числа или значения перечисления (например, AlignText.AlignHCenter
). Таким образом, в примере выше определяются три элемента, каждый из которых представляет данные человека.
Каждый элемент имеет две роли: name и age для хранения имени и возраста человека соответственно.
Делегат создает для каждого элемента модели элемент Text, у которого устанавливается свойство text
:
delegate: Text { text: name + " (" + age + ")" }
Внутри делегата мы можем обратиться к ролям текущего элемента модели по их имени - name и age.
ObjectModel содержит визуальные элементы, которые будут использоваться в представлении. При применении этой модели представление не требует делегата, поскольку объектная модель уже содержит визуальный делегат (элементы). Например:
import QtQuick Window { width: 250 height: 150 visible: true title: "METANIT.COM" ObjectModel { id: itemsModel Rectangle { height: 50; width: 80; color: "red" } Rectangle { height: 50; width: 80; color: "green" } Rectangle { height: 50; width: 80; color: "blue" } } ListView { anchors.fill: parent model: itemsModel spacing: 5 } }
Здесь объект ObjectModel содержит три прямоугольника. И при установке модели ListView отобразит эти прямоугольники: