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

Jérôme Godbout jerome at bodycad.com
Thu Nov 20 17:45:13 CET 2014


Take a look at QVariant doc:  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

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>
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> 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>
> 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> 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>
>> 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
>>> 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/ad3cb161/attachment.html>


More information about the Interest mailing list