Отображение дерева в qml

от автора

image
Однажды один мой знакомый спросил: «Как можно отобразить древовидную структуру в qml?» Получившейся вариант я уже пытался опубликовать на хабре, но в тот раз проспал инвайт… Под катом вторая попытка опубликовать таки статью.
Цель: разработать тестовое приложение отображающее древовидную структуру с помою Qt Quick.
Результат можно посмотреть на GitHub: github.com/1KoT1/QMLPresentTree

Структура данных приложения

В нашем приложении элементы дерева описаны классом TreeItem.

image

Свойство 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *