0
votes

I have an example multi-level ListModel:

ListModel{
    id: myModel
    ListElement{
        name: "File"
        subItems:[
            ListElement{
                name: "Open"
            },
            ListElement{
                name: "Open Recent"
                subItems:[
                    ListElement{
                        name: "Bla.txt"
                    }
                ]
            },
            ListElement{
                name: "Save"
            },
            ListElement{
                name: "Save as"
            },
            ListElement{
                name: "Exit"
            }
        ]
    }
    ListElement{
        name: "Edit"
        subItems:[
            ListElement{
                name: "Undo"
            },
            ListElement{
                name: "Redo"
            },
            ListElement{
                name: "Select All"
            }
        ]
    }
    ListElement{
        name: "Help"
        subItems:[
            ListElement{
                name: "About"
            }
        ]
    }
}

Which I want to display as Menu. From here I know how to iterate model inside of Menu component. But because I have multi-level structure I should check either second level is Menu or MenuItem. Therefore I use Loader and choose which component to load(check if subItems of the element is undefined):

    MenuBar{
    id: menuBar
    Instantiator{
        id: menuBarRepeater
        model: myModel
        onObjectRemoved: menuBar.removeItem( object )
        delegate: Loader{
            sourceComponent: myModel.get(index)["subItems"]? subMenuLoader : menuItemLoader
            onLoaded: {
                item.name = model.name;
                if(myModel.get(index)["subItems"]){
                    item.parentIndex = index;
                    item.model = model
                    menuBar.insertMenu( index, item )
                }else{
                    menuBar.insertItem( index, item )
                }
            }
        }
    }
}

Finally I need to add one more Instantiator for third level of menu. I could do it recursively, but for example purpose I'll assume that I have max. 3 levels. So the components that will be loaded in code above are:

    Component{
    id: menuItemLoader
    MenuItem{
        property var name
        text: name
    }
}

Component{
    id: subMenuLoader
    Menu{
        id: subMenu
        property var name
        property var parentIndex: index
        property var model
        title: name
        Instantiator{
            model: model
            onObjectRemoved: menuBar.removeItem( object )
            delegate: Loader{
                sourceComponent: myModel.get(parentIndex)["subItems"].get(index)["subItems"] ? subMenuLoader : menuItemLoader
                onLoaded: {
                    item.name = model.name;
                    if(myModel.get(parentIndex)["subItems"].get(index)["subItems"]){
                        subMenu.insertMenu( index, item )
                    }else{
                        subMenu.insertItem( index, item )
                    }
                }
            }
        }
    }
}

My problem is that the model that will be passed to the second level is QQmlDMListAccessorData and is not iterable. Is there any way to get children of the Intantiator model item?

1
Wait, your title refers to multi-level menus, and you gave a ton of code describing your multi-level structure, but your question is just about getting the children of an Instantiator?JarMan
The menu should be also multi-level, which leads to Instantiator and the problem getting its children. But I'm also opened for any other ideas how to dynamically build a multi-level menu from multi-level structurePaulPonomarev
Did you try Instantiator's objectAt method?JarMan
Yes, menuBarRepeater.objectAt(index) returns nullPaulPonomarev

1 Answers

0
votes

So, the workaround I have found is: instead of passing the model (which has type QQmlDMListAccessorData) to subMenu, as a second-level Instantiator model I used myModel.get(parentIndex)["subItems"].get(index), which addresses to ListElement, which for QML has type QQmlListModel(%index%) and can be used exactly as its parent (myModel itself)