Access and Change QList<QObject*> dynamic property in QObject*



  • I got DynamicObject Class inherited from QObject

    This is Data Structure of my Data

    (Object/Property : Data Type/Class)

    • rootObj : DynamicObject
      • ItemsSource : QList<QObject*>
        • [0] : DynamicObject*
          • Name : QString
          • Status : Enum
        • [1] : DynamicObject*
        • [2] : DynamicObject*
        • [3] : DynamicObject*

    I can set the Name of item in list like this.

    rootObj->property("ItemsSource").value<QList<QObject*> >()[3]->setProperty("Name", "New Campaign Name");
    

    But I can't set an item to new object like this

    rootObj->property("ItemsSource").value<QList<QObject*> >()[3] = rootObj->property("ItemsSource").value<QList<QObject*> >()[9];
    

    I tried Pointer Referrence like this but it doesn't work.

    void setObject(QObject *& obj, QObject * obj2)
    {
        obj = obj2;
    }
    
    setObject(rootObj->property("ItemsSource").value<QList<QObject*> >()[3], 
        rootObj->property("ItemsSource").value<QList<QObject*> >()[9]);
    

    I also want to remove/insert item as well.

    Any one know why? and how to do it?


  • Qt Champions 2016

    @Dong said:
    Hi
    Do you try to copy QObject based classes ?

    you void setObject(QObject *& obj, QObject * obj2)
    seem to use the = operator
    and if u read in
    http://doc.qt.io/qt-5.5/object.html#qt-objects-identity-vs-value

    "Therefore, QObject and all subclasses of QObject (direct or indirect) have their copy constructor and assignment operator disabled."

    It seems that its not allowed. Not sure if you copy actual Objects or just mere pointers.



  • @mrjj
    Thanks for your notice about the "Copy Constructor & Assignment Operator Disabled"
    May be I had to build my own "Set" function to copy Object's Properties one by one.

    There is an other question in my post.
    My rootObj also have "SelectedItems" Property
    So, I want to set a list of selected items from "ItemsSource"
    And Insert/Remove/Re-Assign an item into/from "SelectedItems" later.

    Can you help me with this?


  • Qt Champions 2016

    @Dong
    Hi
    The SelectedItems is a Qlist ?
    Each Property is QVariant.
    so you could make
    QLIst<QVariant> SelectedItems;
    and just use the normal Qlist add/remove functions.

    I have not tried stuffing a list of variant into a property so not sure how to do that.
    update:
    ahh it has tolist function
    http://doc.qt.io/qt-5.5/qvariant.html#toList
    So you can take out the QList again from the variant and then
    add/remove. and then put it back into property.

    You can get list of all properties this way
    http://doc.qt.io/qt-5/qobject.html#dynamicPropertyNames


  • Qt Champions 2016

    Ouch, my head hurts, 7 operators and 4 function calls on a single line is a bit much for me personally.
    Your problem is that you take the variant's value by QVariant::value, which creates a shallow copy of your list. I'm pretty sure that variant was not intended to store properties in this way, since it doesn't provide a function to operate on the actual variable.

    If you want to change the lists you'd need to do something like this:

    // Take the list
    QObjectList properties = rootObj->property("ItemsSource").value<QObjectList>();
    // Do modify, insert, delete w/e
    ...
    // Update the property
    rootObj->setProperty("ItemsSource", QVariant::fromValue(properties));
    


  • @mrjj & @kshegunov :

    Thanks for your help.

    I already thought about kshegunov solution. completely re-assign the ItemsSource Property.
    But it seem to be "dummy" and I want to find some other way like (pointer / reference or something else)

    I'm more familiar with C# where all Object are reference type so we can modify it directly.

    Anyway, Thanks again !


  • Qt Champions 2016

    @Dong said:

    But it seem to be "dummy" and I want to find some other way like (pointer / reference or something else)

    Well, you depend on what the library has provided for you, and since QVariant will not provide you with a reference you can't modify its contents directly. In all probability the variant type is correctly denying direct access (internally it a union in a struct) as the QVariant class can't be sure what exactly it's storing (it just holds a pointer to data). That's the reason you use template functions to convert from/to variant type.

    I'm more familiar with C# where all Object are reference type so we can modify it directly.

    This is true for FORTRAN as well, and is much error prone. Imagine when you pass an immutable string to a function. The function can change it at any point thus breaking the program stack. This is a classical example why FORTRAN is not type safe. C++ is a bit more evolved in that matter, providing you with copious amounts of ways to ensure that your types will not be corrupted by external means. C# of course is much cleaner than FORTRAN, and allows the variables to be passed as const, but in C++ the by value or by reference passing of arguments/objects is in the hands of the program designer and the language does not presume to know what you want to achieve.



  • @kshegunov :

    Can you explain this?

    //I can set the Name of item in list like this.
    rootObj->property("ItemsSource").value<QList<QObject*> >()[3]->setProperty("Name", "New Campaign Name");
    
    //But I can't set an item to new object like this
    rootObj->property("ItemsSource").value<QList<QObject*> >()[3] = rootObj->property("ItemsSource").value<QList<QObject*> >()[9];
    
    
    Edit:
    
    I thought I found the answer:
    As Kshegunov said: QVariant::value create a Shallow Copy of QList<QObject*> so
       - This Shallow Copy list completely different with the original list.
       - But the QObject* Pointer in that Copy List still point to the same addess as the Original Pointer.
    
    That why we can set individual Property, but cannot replace the Object.

  • Qt Champions 2016

    @Dong
    Hello,
    Sorry for the late reply. Yes, you've got the essence of it. Qt's containers (QList included) are pretty smart in respect to copying, they will not copy the actual data until you change it. They are implicitly shared. This is done so you can return and copy the container many times, but in actuality internally only a pointer is reassigned and reference counter updated. When you call a non-const function on that list, Qt checks the reference counter and if more than one object is attached to the data, then and only then the data is detached (copied). When you put your list in the QVariant it is stored by value (making a shallow copy), but QVariant will return a shallow copy as well (meaning the data will not be changed, only the internal pointer reassigned and reference counter incremented).

    Now, for your particular case:
    The first line of code works, because you don't modify the list, but take an element (which is a pointer) and modify the object the list is holding reference to. This doesn't cause the list data to be copied. The second line you have, doesn't work, because you're changing the list data (assigning a new value to a list's element), which causes the list data to be detached and in practice, you're operating on a completely different set of data.

    Here is a reference if you're interested in the way QList and other containers manage their data, and what implicit sharing is.



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