How do I form a Listview containing mixed items



  • I'm new to QML and have been struggling with building a ListView from data of varying content. I have a UI requirement to display content of varying type, ie. where the delegate changes depending on the type of the item. Now the actual data to display comes from a C++ "node" list (QAbstractItemModel). Some of the nodes have peripheral devices. The desire is to display both the nodes and any peripherals in a flat list with a custom sort.

    I've managed to cook up a solution that involves inspecting the node list using onCompleted handlers, and creating lightweight javascript objects that hold the underlying data (be that a node or a peripheral). These "proxy" model items are dynamically added to a ListModel property on the view with the (node / peripheral) delegate being selected by a Loader.

    The whole thing feels wrong, and importantly does not handle changes to the underlying C++ model (eg. firmware update flag).

    So the question is how do I create a proxy model for a ListView where the model items are not of the same type, eg. where the model items are a mixture of nodes and peripherals?

    ========================

    QML code snippet of what I currently have follows

    ListView {

    id : listView
    property ListModel nodesModel: ListModel {}
    property var nodeInfo : []
    
    Repeater {  // <<========== Purely here to provide an imperative-like hook to process the underlying mode
    
        model: nodesData.nodesModel   // <<============  C++ QAbstractItemModel
        delegate: Item {
            Component.onCompleted: {
                listView.nodeInfo.push({
                    "section": hwVariant < 200 ? "chair" : "tools",
                    "heading": moduleFamily,
                    "hwVariant" : hwVariant,
                    "rowType": "system_node",  // <<============ Used to dynamically choose delegate
                    "itemModel" : model,   // <<=========== C++ individual nodes complete with notifyable QPROPERTYs .  Yes they work in a simple context
                });
    
                // Add a peripheral if this node has an associated function key
                if (model.functionKeyInfo.hasOwnProperty("required") && model.functionKeyInfo.required) {
                    listView.nodeInfo.push({
                        "section" : "chair",
                        "heading" : model.functionKeyInfo.heading,
                        "rowType" : "function_key",
                        "itemModel" : model.functionKeyInfo,
                    });
                }
            }
        }
    
        Component.onCompleted: {
            // sort nodesInfo by section, then rowType, then hwVariant, then serial number
            listView.nodeInfo.sort(Helpers.fieldSorter([
               {field : 'section', order : ["chair", "tools"]},
               {field : 'rowType', order : ['system_node', 'function_key']},
               'hwVariant',
               'serial'
            ]));
    
            listView.nodeInfo.forEach( function (ni) {
                // translate fields then append to the listView model
                ni.section = qsTrId("gui.systemSummary." + ni.section);
                listView.nodesModel.append(ni);
            });
        }
    }
    

    // Actual delegates down here...
    // The "system_node" rowTypes use a delegate that queries the C++ model directly
    // The "function_key" rowTypes use a delegate that queries the peripheral model

    }


  • Moderators

    I think you should:

    • make your Model more flexible
    • make a delegate which adjusts automatically
    • remove all that unnecessary logic from QML, move as much to C++ as possible

    How to go about it?

    • define common API for both peripheral and node model
    • use that common API to create single C++ ItemModel which you will pass to QML
    • make a Delegate which will change it's look depending on values returned by the API. Use a Loader if you must (to load either NodeDelegate or PeripheralDelegate), or if possible use single component which adjusts dynamically

    Sorry for being rather vague, but I don't now your system.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.