Однажды один мой знакомый спросил: «Как можно отобразить древовидную структуру в qml?» Получившейся вариант я уже пытался опубликовать на хабре, но в тот раз проспал инвайт… Под катом вторая попытка опубликовать таки статью.
Цель: разработать тестовое приложение отображающее древовидную структуру с помою Qt Quick.
Результат можно посмотреть на GitHub: github.com/1KoT1/QMLPresentTree
Структура данных приложения
В нашем приложении элементы дерева описаны классом TreeItem.
Свойство content хранит некоторое содержимое элемента. Для тестового приложения вполне подойдёт строка.
Каждый экземпляр элемента имеет список содержащихся в нём подэлементов – childItems. Таким образом строится дерево.
Свойство isOpen хранит состояние списка внутренних элементов: развёрнут или скрыт.
Свойство hasChild показывает, имеются ли дочерние элементы. Можно было бы обойтись использованием !item.childItems().isEmpty(), но для простоты дальнейшего использования ввёл поле hasChild.
Код реализующий данный класс см. в.
В model.h и model.cpp описана модель данных приложения. Модель содержит единственное свойство – дерево элементов.
В создаю модель, представление и экспортирую модель в qml. Контроллер отсутствует, т. к. нет функционала, кроме отображения.
Отображение дерева в qml
Теперь переходим к самому интересному. Опишем отображение нашей древовидной структуры с помощью qml.
Главный файл qml содержит следующий код:
import QtQuick 2.0 Rectangle { width: 360 height: 360 ListView{ anchors.fill: parent model: programmModel.tree delegate: ItemView{} } }
Основная идея в следующем: Отображаем плоский список элементов первого уровня. Делегат, описывающий элемент содержит плоский список для отображения подэлементов. И т. д. по структуре дерева.
Окно целиком заполнено элементом ListView. ListView отображает плоский список и позволяет прокручивать его. В качестве модели указываю наше дерево. По сути это плоский список элементов, каждый из которых в свою очередь содержит список подэлементов. Отображение каждого элемента описано в ItemView.qml:
import QtQuick 2.0 Row{ id: itemView Text{ width: 10 height: 10 text: modelData.hasChild? modelData.isOpen ? "-" : "+" : "" MouseArea{ anchors.fill: parent onClicked: modelData.isOpen = !modelData.isOpen; } } Column{ Text{ text: modelData.content } Loader{ source: modelData.isOpen ? "TreeItemsList.qml" : "Empty.qml" } } }
Элемент состоит из вывода содержимого:
Text{ text: modelData.content }
Элемента управления, показывающего наличие подэлементов и позволяющего раскрыть список:
Text{ width: 10 height: 10 text: modelData.hasChild? modelData.isOpen ? "-" : "+" : "" MouseArea{ anchors.fill: parent onClicked: modelData.isOpen = !modelData.isOpen; } }
Списка поделементов:
Loader{ source: modelData.isOpen ? "TreeItemsList.qml" : "Empty.qml" }
Список подэлементов надо отображать только, когда он открыт. Для этого использую элемент Loader. В закрытом состоянии в него подгружается Empty.qml – прямоуголник размером 0 на 0. Отображение отрытого списка подэлементов описано в TreeItemsList.qml.
Рассмотрим его:
import QtQuick 2.0 Column{ Repeater{ model: modelData.childItems delegate: ItemView{} } }
Построение вертикального списка проиходит с помощью комбинации элементов Column и Repeater. В отличии от ListView Column не позволяет прокручивать содержимое и занимает всё небходимое пространство для отображение внутренних элементов. Прокрутка дерева целиком обеспечивается с помощью ListView в главном файле.
Для отображения подэлементов используется тотже делегот, что и в списке верхнего уровня. Таким образом каждый элемент может отобразить свои поэлементы. Вложенность ограничена только системными ресурсами.
Благодаря использованному подходу выполняется ещё одно важное требование: визуальное дерево строится только для открытых элементов, т. е. не тратятся лишние системные ресурсы.
ссылка на оригинал статьи http://habrahabr.ru/post/197110/
Добавить комментарий