qtqmlqqmlcomponentqquickitemqqmlapplicationengine

How to create a new QQuickItem copy from scratch on C++ side with the same properties as an existing one


I have a QQuickItem fetched from C++ side like this.

QQuickItem * my_item = qmlEngine->rootObjects()[0]->findChild<QQuickItem*>("ItemObjectName");

my_item is valid & has all the properties set on to it.

Scenario
I have 2 windows which need this QQuickItem to be drawn on alterantively. I want to render this my_item to a different window. This works perfectly fine as long as I set the Parent of the my_item to the other window

// the_other_window is a QQuickWindow
QQuickWindow * the_other_window;

// here I set parent
my_item->setParentItem(the_other_window->contentItem());

This requires me to do setParentItem again back to my_item's original window otherwise it goes invisible on the original window. This is working but gives me unnecessary dependency. Instead I am trying to create a copy of the QQuickItem & do a setParentItem on that. By copying like this:

QQuickItem * item_copy = new QQuickItem(my_item);

Question: I want to make item_copy as exactly the same as my_item. I learnt that QQuickItem is not copyable. So, want to set all properties of my_item into item_copy. Thus recreating my_item from scratch. How can I do this? What properties should I copy primarily? width, height, x, y & what else?

Is there a method to copy all the valid properties into this new one without copying each one by one?


Solution

  • To copy all the properties you must use the metaobject(), through this we obtain the properties and we can copy them as shown below. Note: not all properties can be written, for this we check with the method isWritable():

    QQuickItem *copyQQuickItem(QQuickItem *item){
        QQuickItem *item_Copy = new QQuickItem;
    
        const QMetaObject *mo = item->metaObject();
    
        for (int i = mo->propertyOffset(); i < mo->propertyCount(); ++i){
            if(mo->property(i).isWritable()){
                const char* name = mo->property(i).name();
                item_Copy->setProperty(name, item->property(name));
            }
        }
        return item_Copy;
    }
    

    Example:

    QQuickItem * my_item = engine.rootObjects()[0]->findChild<QQuickItem*>("ItemObjectName");
    QQuickItem *item_copy = copyQQuickItem(my_item);
    
    const QMetaObject *mo = my_item->metaObject();
    
    for (int i = mo->propertyOffset(); i < mo->propertyCount(); ++i){
        if(mo->property(i).isWritable()){
            const char* name = mo->property(i).name();
            qDebug()<<name<<my_item->property(name)<<item_copy->property(name);
            Q_ASSERT(my_item->property(name)==item_copy->property(name));
        }
    }
    

    Output:

    parent QVariant(QQuickItem*, QQuickRootItem(0x55975cfdf520)) QVariant(QQuickItem*, QQuickRootItem(0x55975cfdf520))
    x QVariant(double, 0) QVariant(double, 0)
    y QVariant(double, 0) QVariant(double, 0)
    z QVariant(double, 0) QVariant(double, 0)
    width QVariant(double, 100) QVariant(double, 100)
    height QVariant(double, 100) QVariant(double, 100)
    opacity QVariant(double, 1) QVariant(double, 1)
    enabled QVariant(bool, true) QVariant(bool, true)
    visible QVariant(bool, true) QVariant(bool, true)
    state QVariant(QString, "") QVariant(QString, "")
    baselineOffset QVariant(double, 0) QVariant(double, 0)
    clip QVariant(bool, false) QVariant(bool, false)
    focus QVariant(bool, false) QVariant(bool, false)
    activeFocusOnTab QVariant(bool, false) QVariant(bool, false)
    rotation QVariant(double, 0) QVariant(double, 0)
    scale QVariant(double, 1) QVariant(double, 1)
    transformOrigin QVariant(int, 4) QVariant(int, 4)
    smooth QVariant(bool, true) QVariant(bool, true)
    antialiasing QVariant(bool, false) QVariant(bool, false)
    implicitWidth QVariant(double, 0) QVariant(double, 0)
    implicitHeight QVariant(double, 0) QVariant(double, 0)