Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. How do you simulate a tree view in Qt Quick since it's not included in Controls 1.0?
Forum Updated to NodeBB v4.3 + New Features

How do you simulate a tree view in Qt Quick since it's not included in Controls 1.0?

Scheduled Pinned Locked Moved QML and Qt Quick
23 Posts 13 Posters 24.2k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • ? Offline
    ? Offline
    A Former User
    wrote on last edited by
    #3

    [quote author="Babalas" date="1375223686"]I have a similar requirement for a tree view structure which I'll start having a play with today. I've done collapsible sections in lists so I hope I can extend that to simulate a tree. It is based on https://gist.github.com/elpuri/3753756[/quote]

    Have you had any success with your implementation? Since I'm inexperienced with Qt/QML/Quick, my main hangup was determining how to provide for child branches (expandable subnodes). How would one address this if the model were something like follows:

    @
    ListModel
    {
    ListElement
    {
    text: "Level 1, Node 1"
    }

    ListElement
    {
        text: "Level 1, Node 2"
        elements:
        [
            ListElement
            {
                text: "Level 2, Node 1"
                elements:
                [
                    ListElement
                    {
                        text: "Level 3, Node 1"
                    }
                ]
            },
            ListElement
            {
                text: "Level 2, Node 2"
            }
        ]
    }
    
    ListElement
    {
        text: "Level 1, Node 3"
    }
    

    }
    @

    1 Reply Last reply
    0
    • B Offline
      B Offline
      Babalas
      wrote on last edited by
      #4

      I ended up going with a hybrid between the collapsing sections and a StackView. Then put a breadcrumb trail at the top. So each section acts as the parent and the child nodes end up being a Repeater under that section. Each child has a MouseArea that when clicked pushes itself onto the StackView.
      It isn't a tree view, but in my case it works well enough. Happy to go into more detail if you want

      1 Reply Last reply
      0
      • J Offline
        J Offline
        Jens
        wrote on last edited by
        #5

        I have seen this question pop up quite often so I thought I gave a shot at creating a simple tree view. It is certainly not the full solution as you might expect for 60 lines of QML, but for those of you in desperate need of "simulating" one it might already be sufficient for your use case and it will work fine with the model you suggested above.

        @
        import QtQuick 2.1

        Flickable {
        property var model
        anchors.fill: parent

        contentHeight: content.height
        contentWidth: content.width
        
        Loader {
            id: content
            sourceComponent: treeBranch
            property var elements: model
            property bool isRoot: true
        
            Component {
                id: treeBranch
        
                Item {
                    id: root
        
                    implicitHeight: column.implicitHeight
                    implicitWidth: column.implicitWidth + 4
                    Column {
                        id: column
                        x: 2
                        spacing: 2
                        Text { text: !!root.isRoot ? "" : " " }
                        Repeater {
                            model: elements
                            Row {
                                spacing: 2
                                Rectangle {
                                    width: 18
                                    height: 18
                                    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
                                    }
                                }
                                Text { text: model.text }
                                Loader {
                                    id: loader
                                    height: expanded ? implicitHeight : 0
                                    property bool expanded: false
                                    property var elements: model.elements
                                    property var text: model.text
                                    sourceComponent: (expanded && !!model.elements) ? treeBranch : undefined
                                }
                            }
                        }
                    }
                }
            }
        }
        

        }
        @

        You will also need to copy this expander pixmap or make your own:
        !http://i.imgur.com/DcRU8xd.png(expander)!

        If you will use it with the Qt Quick Controls, you can simply replace the Flickable with a ScrollView and remove the content size definition from the root item.

        Using it it should be pretty straight forward:

        @

        import QtQuick 2.1

        Rectangle {

        width: 360
        height: 480
        
        ListModel {
            id: treemodel
            ListElement { text: "Level 1, Node 1" }
            ListElement {
                text: "Level 1, Node 2"
                elements: [
                    ListElement { text: "Level 2, Node 1"
                        elements: [
                            ListElement { text: "Level 3, Node 1" }
                        ]
                    },
                    ListElement { text: "Level 2, Node 2" }
                ]
            }
            ListElement { text: "Level 1, Node 3" }
        }
        
        TreeView {
            anchors.fill: parent
            model: treemodel
        }
        

        }
        @

        Edit: added a screenshot
        !http://i.imgur.com/QDhNfco.png(screenshot)!

        1 Reply Last reply
        0
        • B Offline
          B Offline
          Babalas
          wrote on last edited by
          #6

          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

          1 Reply Last reply
          0
          • _ Offline
            _ Offline
            _dmp
            wrote on last edited by
            #7

            [quote author="Jens" date="1375874127"]I have seen this question pop up quite often so I thought I gave a shot at creating a simple tree view. It is certainly not the full solution as you might expect for 60 lines of QML, but for those of you in desperate need of "simulating" one it might already be sufficient for your use case and it will work fine with the model you suggested above.
            [/quote]

            Thank you very much, Jens!

            Its work.

            Can you show sample code how create this ListModel in C++ dinamically?

            @
            ListModel {
            id: treemodel
            ListElement { text: "Level 1, Node 1" }
            ListElement {
            text: "Level 1, Node 2"
            elements: [
            ListElement { text: "Level 2, Node 1"
            elements: [
            ListElement { text: "Level 3, Node 1" }
            ]
            },
            ListElement { text: "Level 2, Node 2" }
            ]
            }
            ListElement { text: "Level 1, Node 3" }
            }
            @

            Regards!

            1 Reply Last reply
            0
            • P Offline
              P Offline
              philk
              wrote on last edited by
              #8

              [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?

              1 Reply Last reply
              0
              • J Offline
                J Offline
                Jens
                wrote on last edited by
                #9

                Here is an updated example using qt quick controls:

                @
                import QtQuick 2.1
                import QtQuick.Controls 1.0

                ScrollView {
                id: view

                property 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)!

                1 Reply Last reply
                0
                • Aaron HouA Offline
                  Aaron HouA Offline
                  Aaron Hou
                  wrote on last edited by
                  #10

                  It's wonderful! Thank you, Jens!

                  1 Reply Last reply
                  0
                  • L Offline
                    L Offline
                    loran
                    wrote on last edited by
                    #11

                    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.1

                    ApplicationWindow {
                    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@

                    1 Reply Last reply
                    0
                    • G Offline
                      G Offline
                      gemmell
                      wrote on last edited by
                      #12

                      For others finding this thread, there's also:
                      http://www.codeproject.com/Articles/664041/QML-QtQuick-TreeView-Model-Part-II

                      Another 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.

                      1 Reply Last reply
                      0
                      • H Offline
                        H Offline
                        hmuelner
                        wrote on last edited by
                        #13

                        [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"

                        Helmut Mülner

                        1 Reply Last reply
                        0
                        • H Offline
                          H Offline
                          hmuelner
                          wrote on last edited by
                          #14

                          It would be really nice if the model could be a C++ QAbstractItemModel that is set with setContextProperty.

                          Helmut Mülner

                          1 Reply Last reply
                          0
                          • H Offline
                            H Offline
                            HennsWoerst
                            wrote on last edited by
                            #15

                            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.

                            1 Reply Last reply
                            0
                            • A Offline
                              A Offline
                              apmontgo
                              wrote on last edited by
                              #16

                              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

                              1 Reply Last reply
                              0
                              • A Offline
                                A Offline
                                apmontgo
                                wrote on last edited by
                                #17

                                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

                                1 Reply Last reply
                                0
                                • O Offline
                                  O Offline
                                  onek24
                                  wrote on last edited by
                                  #18

                                  [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.

                                  1 Reply Last reply
                                  0
                                  • O Offline
                                    O Offline
                                    onek24
                                    wrote on last edited by
                                    #19

                                    [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.

                                    1 Reply Last reply
                                    0
                                    • JKSHJ Offline
                                      JKSHJ Offline
                                      JKSH
                                      Moderators
                                      wrote on last edited by
                                      #20

                                      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/

                                      Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                                      1 Reply Last reply
                                      0
                                      • JKSHJ Offline
                                        JKSHJ Offline
                                        JKSH
                                        Moderators
                                        wrote on last edited by
                                        #21

                                        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/

                                        Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                                        1 Reply Last reply
                                        0
                                        • O Offline
                                          O Offline
                                          onek24
                                          wrote on last edited by
                                          #22

                                          Oh thats sweet, i'll wait until the official release. Thanks for your information.

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved