Use a custom item as a children declared as a property (like delegate in views)



  • I'm trying to create an object where you can declare a custom item that will be inserted in my custom object. But I don't know how to use this delegate later in my code.
    Example:

    // MyObject.qml
    Row {
        property var customItem
        ItemBefore { }
        // This where I don't know how to use the custom item
        customItem {
            // That would be even better if I could set properties 
            // that are used by the item (width, height, ...)
            // like with a regular QML object
            someProperties: true
        }
        ItemAfter { }
    }
    
    // Main.qml
    Item {
        MyObject {
            customItem: Rectangle { color: "#FF0000" }
        }
        MyObject {
            customItem: Rectangle { color: "#00FF00" }
        }
        MyObject {
            customItem: Rectangle { color: "#0000FF" }
        }
    }
    

    The behavior I'm looking for is similar to the one used by ListView and GridView with the delegate property.
    Can anyone help me ?
    MoaMoaK



  • The easiest way I can think to do this in pure QML is use a Repeater instead of your custom object. It takes a delegate but does not impose any particular layout. You can let the items position themselves (e.g. using x/y properties in the delegate based on the model) or you can control their layout yourself by using the itemAdded signal and adjusting properties of the item there.

    But assuming that does not meet your needs, and since it does not answer your question, I would wrap your delegate in a Component so that you can easily instantiate it using createObject():

    main.qml

    import QtQuick 2.6
    import QtQuick.Window 2.2
    Window {
        visible:true; width:640; height:480; title:"Replicator"
        Replicator {
            copies: 15
            Component {
                Rectangle {
                    width:200; height:100
                    color:Qt.rgba(255,0,0,0.2); border.color:'red'
                    property alias label: t.text
                    Text { id:t; anchors.centerIn:parent }
                }
            }
        }
    }
    

    Replicator.qml

    import QtQuick 2.0
    Item {
        id: root
        anchors.fill: parent
        property int copies: 5
        default property var template
        Component.onCompleted: {
            for (var i=copies;i--;) {
                var props = {
                    label: "I'm item #"+i,
                    x: Math.random()*root.width/2,
                    y: Math.random()*root.height/2
                };
                template.createObject(root, props);
            }
        }
    }
    

    This produces a result like:
    0_1510358350481_Screen Shot 2017-11-10 at 4.58.29 PM.png

    In the example above I've used the default keyword to allow your delegate without a label. This is purely optional.

    There may be a way to do this without a Component, but I don't know what it is. The page on Dynamic QML Object Creation says:

    There are two ways to create objects dynamically from JavaScript. You can either call Qt.createComponent() to dynamically create a Component object, or use Qt.createQmlObject() to create an object from a string of QML.

    You don't have a string of QML, and so you must use a component.

    A true delegate object like ListView and Repeater accept would require some way to derive a component from an instance, and that does not appear to me to be possible in pure QML.



  • @MoaMoaK Using a Loader should perfectly do want you want to achieve:

    // MyObject.qml
    Row {
        property alias customItem: loader.sourceComponent
        ItemBefore { }
        Loader {
          id: loader
          // Just a bunch of custom properties
          property int widthOfCustomItem: 100
          property int heightOfCustomItem: 100
        }
        ItemAfter { }
    }
    
    // Main.qml
    Item {
        MyObject {
            customItem: Rectangle {
              color: "#FF0000"
              // You can use all properties of the Loader inside your customItem
              width: widthOfCustomItem
              height: heightOfCustomItem
            }
        }
        MyObject {
            customItem: Rectangle { color: "#00FF00" }
        }
        MyObject {
            customItem: Rectangle { color: "#0000FF" }
        }
    }
    


  • @DuBu Sorry I'm a bit late, but really using Loader was THE solution I wanted, thx a lot.
    It works perfectly.


Log in to reply
 

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