[Interest] Best model type for shared data between C++ and QML, as well as insertion and removal on both sides.

Nuno Santos nunosantos at imaginando.pt
Thu Nov 20 17:48:21 CET 2014


I will take a look! Thanks!! :)

> On 20 Nov 2014, at 16:45, Jérôme Godbout <jerome at bodycad.com> wrote:
> 
> Take a look at QVariant doc:  http://qt-project.org/doc/qt-5/qvariant.html <http://qt-project.org/doc/qt-5/qvariant.html>
> you will find the typedef: http://qt-project.org/doc/qt-5/qvariant.html#QVariantMap-typedef <http://qt-project.org/doc/qt-5/qvariant.html#QVariantMap-typedef>
> 
> in javascript use assign with the named array (dictionary) object.  You will have to assign the whole structure when doing the modification into Qml.
> 
> C++ :
> property QVariantMap myModel READ ... WRITE ...
> Just read the QVariantMap and insert value into it, don't forget to emit the changed.
> 
> Qml:
> myModel: ({ 'patch': patch1_})
> Patch { id: patch1_; name: "Patch 1"}
> 
> // Cannot modify the value directly, need to reassign it. A merge dictionary function "à la jquery extend()" is also a good idea
> function assignModel(name, val)
> {
>    var rv = myModel;
>    rv[name] = val;
>    myModel = rv;
> }
> 
> Binding:
> patch: myModel[''patch']
> 
> 
> On Thu, Nov 20, 2014 at 11:25 AM, Nuno Santos <nunosantos at imaginando.pt <mailto:nunosantos at imaginando.pt>> wrote:
> Jerome,
> 
> Thanks for your reply. Got the idea.
> 
> Can you point me to useful resources on how to use QVariant on this case? Still didn’t get it how do you use it in this case.
> 
> Regards,
> 
> Nuno
> 
>> On 20 Nov 2014, at 16:22, Jérôme Godbout <jerome at bodycad.com <mailto:jerome at bodycad.com>> wrote:
>> 
>> It's not really a model, but lesser pain to modify data on both end. It's a QVariant basic type.  I also try to make a template wrapper that enclose the QQmlListProperty and send signal before/after append, clear:
>> 
>> // Those function are required to make the element opearator= and operator[] into Qml scripts (static function with object pointer must also be declared to get the full behavior of a list)
>> void append(T* value) { beforeChanged(); list_.append(value); listChanged(); } 
>> int count() { return list_.count(); } 
>> T* at(int index) { return list_.at(index); } 
>> void  clear() { beforeChanged(); list_.clear(); listChanged(); }
>> 
>> QList<QPointer<T>> list_;
>> 
>> It does work. But still emit too many changed when assigning element for a long list. Assigning 1000 elements will emit 1001 changed signals. 1 for the clear, and 1000 append. When assigning, would need to known when the transaction start/end to disable the signals and emit the signal only once when the assign finish. But haven't find a way to do so yet. Since the List item are readonly, only their content change, the Qml binding on the list does not get revaluate when doing append or clear on them. To revaluate the binding we have to emit that the list changed somehow (here the listChanged was connect to it).  This is why I went QVariant (QVariantList or QVariantMap) for those, just modify the value and assign it once, emit a single changed and the value is writable from Qml.
>> 
>> The QQmlListProperty is good when doing a list from C++ and passing it to Qml, but not firendly if Qml want to modify them (else you have to make a special function that will assign and emit the changed manually).
>> 
>> On Thu, Nov 20, 2014 at 10:38 AM, Nuno Santos <nunosantos at imaginando.pt <mailto:nunosantos at imaginando.pt>> wrote:
>> Jerome,
>> 
>> Thanks for your feedback. In time between your reply I have achieved precisely what you have said in your reply.
>> 
>> Which options would you consider for this problem?
>> 
>> What about QVariantMap? Is it a model? Can’t find 5.3 documentation for it.
>> 
>> Regards,
>> 
>> Nuno
>> 
>> 
>>> On 20 Nov 2014, at 15:24, Jérôme Godbout <jerome at bodycad.com <mailto:jerome at bodycad.com>> wrote:
>>> 
>>> Hi,
>>> My observation with the QQmlListProperty so far. You can assign to it but only with javascript array, list, etc. It does not allow diect array object instanciate. The following should work:
>>> 
>>> presets: [patchSet1]
>>> PatchSet 
>>> {
>>>             id: patchSet1
>>>             name: "Preset 1"
>>>             patches: [patch1, patch2] 
>>>  }
>>> Patch { id: patch1; name: "Patch 1"}
>>> Patch { id: patch2; name: "Patch 2"}
>>> 
>>> You cannot assign one QQmlListProperty to another one
>>>  
>>> presets: myOtherQQmlListProperty   // Won't work
>>> 
>>> But you can make yourself a javascript function that take every element of a QQmlListProperty and put them into a JS Array and assign that array to the list
>>> 
>>> function convertQQmlListPropertyToJSArray(myQQmlList)
>>> {
>>>    var rv = [];
>>> for(var i = 0; i < myQQmlList.length; ++i)
>>> {
>>>   rv.push(myQQmlList[i];
>>> }
>>> return rv;
>>> }
>>> 
>>> presets: convertQQmlListPropertyToJSArray(myOtherQQmlListProperty)  // will work
>>> 
>>> Another point, the QQmlListProperty will clear and append every element into it, it does not emitChanged when doing so, you have to create another signal.
>>> Personnaly, for those exchange, I prefer to go QVariantMap, you still have to emit the change and reassign the whole map every time, but it's easy to manipulate into Javascript. QQmlListProperty are only fun if populated from C++ and only read from Qml.
>>> 
>>> 
>>> On Thu, Nov 20, 2014 at 9:38 AM, Nuno Santos <nunosantos at imaginando.pt <mailto:nunosantos at imaginando.pt>> wrote:
>>> Hi,
>>> 
>>> I need to implement a model class that allows me to have the data in C++ but exposed to QML.
>>> 
>>> The data will need to be exposed to QML and it will be necessary to write from QML to that model as well.
>>> 
>>> The C++ side will be in charge of the data persistence.
>>> 
>>> I started with QQmlListProperty and it works for having data exposed from C++ to QML. The problem is that I also need to dynamically instantiate data on the QML side and write to the list. That doesn’t seem to be possible, or, if it is, I don’t know how to get there. So far I have only been able to write to the list, writing the items on the property it self. See example below.
>>> 
>>> What I am trying to do with QQmlListProperty is possible or should I adopt another model type such as QAbstractListModel?
>>> 
>>> Thanks
>>> 
>>> Nuno
>>> 
>>> Example:
>>> 
>>> // works
>>> PatchSetManager {
>>>     id: patchManager
>>> 
>>>     presets: [
>>>         PatchSet {
>>>             name: "Preset 1"
>>>             patches: [
>>>                 Patch {
>>>                     name: "Patch 1"
>>>                 },
>>>                 Patch {
>>>                     name: "Patch 2"
>>>                 }
>>>             ]
>>>         }
>>>     ]
>>> }
>>> 
>>> // doesn’t work
>>> 
>>> var patchSet = Qt.createQmlObject('import Imaginando 1.0; PatchSet {}', patchManager);
>>> 
>>> if (patchSet)
>>> {
>>>     console.log("object created successfully");
>>> }
>>> 
>>> patchSet.name = "test"
>>> 
>>> var patch = Qt.createQmlObject('import Imaginando 1.0; Patch {}', patchSet);
>>> 
>>> if (patch)
>>> {
>>>     patchSet.patches.append(patch)
>>>     console.log(patchSet.patches + " length: " + patchSet.patches.length)
>>> }
>>> 
>>> 
>>> _______________________________________________
>>> Interest mailing list
>>> Interest at qt-project.org <mailto:Interest at qt-project.org>
>>> http://lists.qt-project.org/mailman/listinfo/interest <http://lists.qt-project.org/mailman/listinfo/interest>
>>> 
>> 
>> 
> 
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20141120/7af7c6ad/attachment.html>


More information about the Interest mailing list