Qt nested ListView or can I use TreeView



  • I am working on a project where I want to have a GUI like this:

    (I cant figure out how to inset pictures here)
    http://i.stack.imgur.com/ZGfps.png

    I have a list of my class (the blue one), and it has a list of the green class, so far my C++ structure is good, and I can get data from C++ in qml and vice versa, but I am not sure how to make the GUI work correct, I have triede with nested ListViews, but it seems like that I have no access to the outer ListView model from the inner ListView..

    I am pretty new to qml, and yesterday I found the TreeView, but to me it looks like that is only usefull if you have a table structure. Is there some qml that I dont know about that can help me with this?

    I have tried this with nested ListViews, the idea beeing that the inner ListView get a object of the green class as model.

    ListView {
    id: userView
    anchors.fill: parent
    model: myModel
    delegate: Rectangle {
        width: 900
        height: 200
        Column {
            id: col
            anchors.left: parent.left
            anchors.right: parent.right
    
            Item { height: 10 }
            Text {
                text: model.type + " " + model.name
            }
            Row {
                spacing: 8
                Button {
                    id: addLevel
                    width: 80
                    text: "Add Level"
                    enabled: setVisible
                    elevation: 1
                    backgroundColor: Theme.primaryColor
                    onClicked: {
                        myModel.insertLevel(index)
                    }
                }
                Button {
                    id: delTariff
                    width: 80
                    text: "Delete User"
                    enabled: setVisible
                    elevation: 1
                    backgroundColor: Theme.primaryColor
                    onClicked: {
                        myModel.removeTariff(index)
                    }
                }
                Button {
                    id: delLevel
                    width: 80
                    text: "Delete Level"
                    enabled: setVisible
                    elevation: 1
                    backgroundColor: Theme.primaryColor
                    onClicked: {
                        myModel.removeLevel(index, 0)
                    }
                }
            }
            Text {
                text: model.levels
            }
            Row {
                spacing: 8
                Repeater {
                    model: myModel.levelStructModel(userView.index)
                    Rectangle {
                        height: 30
                        width: 30
                        color: "blue"
                    }
                }
            }
        }
    }
    

    I also have problem with the program craching after adding or deleting stuff, I tried add the QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership) in the contructor of myModel, but without any luck.



  • @CocoJoe
    Consider classes SomeModel and SubModel:
    SomeModel - model for outer ListView;
    SubModel - model for inner ListView.
    SubModlItem - items in SubModel.

    SomeModel.h

    class SomeModel : public QAbstractListModel
    {
        Q_OBJECT
    public:
        enum SomeModelRoles{
            SOMETEXT = Qt::UserRole+1,
            SUBMODEL
        };
        //....
        // QAbstractItemModel interface
    public:
        int rowCount(const QModelIndex &parent) const;
        QVariant data(const QModelIndex &index, int role) const;
        QHash<int, QByteArray> roleNames() const;
    
    protected:
        QVector<SubModel*> m_models;
        QHash<int, QByteArray> m_roles;
    };
    

    SomeModel.cpp

    QVariant SomeModel::data(const QModelIndex &index, int role) const
    {
        if(!index.isValid())
            return QVariant();
    
        if(role == SOMETEXT)
            return m_models.at(index.row())->someText();
        else if(role == SUBMODEL)
            return QVariant::fromValue(m_models.at(index.row()));
    
        return QVariant();
    }
    

    SubModel.h

    class SubModel : public QAbstractListModel
    {
        //...
        Q_PROPERTY(QString someText READ someText WRITE setSomeText NOTIFY someTextChanged)
    
    public:
        enum SubModelRoles{
            COLOR = Qt::UserRole+1
        };
    
       //...
    
        // QAbstractItemModel interface
    public:
        int rowCount(const QModelIndex &parent) const;
        QVariant data(const QModelIndex &index, int role) const;
        QHash<int, QByteArray> roleNames() const;
    
    protected:
        QHash<int, QByteArray> m_roles;
        QVector<SomeItem*> m_items;
        QString m_text;
    };
    

    SubModel.cpp

    QVariant SubModel::data(const QModelIndex &index, int role) const
    {
        if(!index.isValid())
            return QVariant();
    
        if(role == COLOR)
            return m_items.at(index.row())->color();
    
        return QVariant();
    }
    

    some qml file:

    ListView {
                model: someModel // model from C++
                spacing: 10
    
                delegate: Component{
                    Rectangle {
                        width: 200
                        height: col.height
    
                        Column{
                            id: col
                            anchors.left: parent.left
                            anchors.top: parent.top
                            height: list.count*20 + header.height + buttonsRow.height
                            width: parent.width
    
                            Text{
                                id: header
                                width: parent.width
                                height: 40
                                text: someText
                            }
    
                            Row{
                                id: buttonsRow
                                anchors.horizontalCenter: parent.horizontalCenter
    
                                Button{
                                    id: btnAdd
                                    text: qsTr("Add")
                                }
    
                                Button{
                                    id: btnDelete
                                    text: qsTr("Delete")
                                }
                            }
    
                            ListView {
                                id: list
                                model: subModel
                                width: 0.7*parent.width
                                height: count*20
                                anchors.horizontalCenter: parent.horizontalCenter
    
                                delegate: Rectangle {
                                    width: ListView.view.width
                                    height: 20
                                    color: itemColor
                                    border.color: "gray"
                                    border.width: 1
    
                                    MouseArea{
                                        anchors.fill: parent
                                        onClicked: console.log(parent.color)
                                    }
                                }
                            }
                        }
                    }
                }
            }
    


  • @medyakovvit
    Finally I got to implement it.
    It works like a charm thank you very much..

    If you want to score some extra kudos on stackoverflow I have posed the same question there http://stackoverflow.com/questions/37671430/qt-nested-listview-or-can-i-use-treeview

    If you dont I will answer it myself



  • @CocoJoe Welcome.
    You can answer on stackoverflow)