How do you simulate a tree view in Qt Quick since it's not included in Controls 1.0?
-
[quote author="Babalas" date="1375933330"]Similar to what I've ended up with.
!http://i.imgur.com/AICbtqb.png!
From top to bottom:Toolbar with button and breadcrumb (ListView + model)
StackView
Collapsing section for the child nodes (the scenes, who can also have children)
Repeating collapsing sections for properties
TableView
[/quote]Is there any chance you could reveal some code for that? Are the collapsing sections also driven by a model?
-
Here is an updated example using qt quick controls:
@
import QtQuick 2.1
import QtQuick.Controls 1.0ScrollView {
id: viewproperty var model property int rowHeight: 19 property int columnIndent: 22 property var currentNode property var currentItem property Component delegate: Label { id: label text: model.text ? model.text : 0 color: currentNode === model ? "white" : "black" } frameVisible: true implicitWidth: 200 implicitHeight: 160 contentItem: Loader { id: content onLoaded: item.isRoot = true sourceComponent: treeBranch property var elements: model Column { anchors.fill: parent Repeater { model: 1 + Math.max(view.contentItem.height, view.height) / rowHeight Rectangle { objectName: "Faen" color: index % 2 ? "#eee" : "white" width: view.width ; height: rowHeight } } } Component { id: treeBranch Item { id: root property bool isRoot: false implicitHeight: column.implicitHeight implicitWidth: column.implicitWidth Column { id: column x: 2 Item { height: isRoot ? 0 : rowHeight; width: 1} Repeater { model: elements Item { id: filler width: Math.max(loader.width + columnIndent, row.width) height: Math.max(row.height, loader.height) property var _model: model Rectangle { id: rowfill x: view.mapToItem(rowfill, 0, 0).x width: view.width height: rowHeight visible: currentNode === model color: "#37f" } MouseArea { anchors.fill: rowfill onPressed: { currentNode = model currentItem = loader forceActiveFocus() } } Row { id: row Item { width: rowHeight height: rowHeight opacity: !!model.elements ? 1 : 0 Image { id: expander source: "expander.png" opacity: mouse.containsMouse ? 1 : 0.7 anchors.centerIn: parent rotation: loader.expanded ? 90 : 0 Behavior on rotation {NumberAnimation { duration: 120}} } MouseArea { id: mouse anchors.fill: parent hoverEnabled: true onClicked: loader.expanded = !loader.expanded } } Loader { property var model: _model sourceComponent: delegate anchors.verticalCenter: parent.verticalCenter } } Loader { id: loader x: columnIndent height: expanded ? implicitHeight : 0 property var node: model property bool expanded: false property var elements: model.elements property var text: model.text sourceComponent: (expanded && !!model.elements) ? treeBranch : undefined } } } } } } }
}
@!http://i.imgur.com/aUihaC5.png(treeview screenshot)!
-
Unfortunately the example above crashes when I remove any element from the model when the folder in the view is expanded. Tested with Qt 5.2.0 and 5.2.1 on Linux. Test to reproduce:
@import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1ApplicationWindow {
id: window
width: 400
height: 480
title: qsTr("Tree")Timer { interval: 3000 running: true repeat: false onTriggered: { console.log("Removing element"); var obj = tree.model.get(0); console.log(obj.elements); obj.elements.remove(0); } } Component.onCompleted: { var obj = tree.model.get(0); obj.elements.append({ text: "x1" }); obj.elements.append({ text: "x2" }); obj.elements.append({ text: "x3" }); } ListModel { id: modelTree ListElement { text: "All"; elements: []; } } TreeView { anchors.fill: parent id: tree model: modelTree }
}@
Compile and run. Open the root element "All". In 3 seconds the application will activate the timer and will try to remove the first subitem "x1". Result: crash.
@QML debugging is enabled. Only use this in a safe environment.
Removing element
QQmlListModel(0x820b588)
Segmentaion fault@ -
For others finding this thread, there's also:
http://www.codeproject.com/Articles/664041/QML-QtQuick-TreeView-Model-Part-IIAnother way to do it is to map your C++ tree to a flat list and then make it look like a tree without it being a tree. That way you get all the benefits of the ListView only creating objects as you need them. Though obviously the encapsulation and events are somewhat less useful.
A fully expanded tree using the above solutions and a large model could get quite slow.
-
[quote author="loran" date="1393348350"]Unfortunately the example above crashes when I remove any element from the model when the folder in the view is expanded. Tested with Qt 5.2.0 and 5.2.1 on Linux. ...
[/quote]With the current snapshot of Qt5.3-RC the crash does not happen any more. I get a message on the console: "TreeView.qml:15: TypeError: Cannot read property 'text' of null"
-
I am trying to make this (really nice) view work with a QAbstractItemModel but I'm pretty much stuck -.-
My first approach was to return the childItems of a node as model. I wrote a constructor in my model (of type QAbstractListModel) that took a QList<Node*> and returned a new model whenever the view wanted the subnodes of a node. This worked really well for read-only access, but is a mess regarding editing the tree, since I guess the models do not communicate to each other and a model has no idea what happens in another model. So if you delete a node in one model and another model wants to access the children of this model the whole thing crashes, because it does not know there is one node missing (that is my guess at least)
So it seems the only solution for a consistent model is to have only one model that keeps track of every event that happens in the tree. So my second approach was the following: I returned the childnodes of a node as a QList<Node*> and made the data of a node accessible through the Q_PROPERTY macro, e.g. Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged). But now the view does not work anymore because the data of a QObject based model can only be accessed with model.modelData.role and not with model.role like in a QAbstractItemModel. The view would have to deal with two kinds of models and I do not know how to realize this.
Can maybe anybody give me a hint on how I could make this work, it would be very much appreciated. Thank you.
edit: I just realized the second approach would not work anyhow since the view would not be updated in a QObject based model.
-
If you want to make your own Qt Quick TreeView in C++, there's a presentation here:
https://www.qtdeveloperdays.com/sites/default/files/north-america/QtQuickTreeView.pdf -
If you want to make your own Qt Quick TreeView in C++, there's a presentation here:
https://www.qtdeveloperdays.com/sites/default/files/north-america/QtQuickTreeView.pdf -
[quote author="Jens" date="1381914126"]Here is an updated example using qt quick controls:
...[/quote]
A very nice example. It seems like it's not that easy to implement key-events(up, down, ...) for controling this view. I would appreciate it if anyone could come up with an idea.
-
[quote author="Jens" date="1381914126"]Here is an updated example using qt quick controls:
...[/quote]
A very nice example. It seems like it's not that easy to implement key-events(up, down, ...) for controling this view. I would appreciate it if anyone could come up with an idea.
-
If you can wait a bit longer, there will be an official TreeView QML type in the upcoming "Qt 5.5 release":http://blog.qt.io/blog/2015/02/05/licensing-of-new-modules-in-qt-5-5/
-
If you can wait a bit longer, there will be an official TreeView QML type in the upcoming "Qt 5.5 release":http://blog.qt.io/blog/2015/02/05/licensing-of-new-modules-in-qt-5-5/