View Full Version : QQmlPropertyMap, model
sBoff
26th August 2013, 05:15
Hi all,
I’m trying to get my head around this and after much research and testing I feel I must be missing something simple.
I have a QQmlPropertyMap derived object that I am adding to in my C++ code. I am then binding to the data in my QML – this is all working great. When I update the value on the C++ side my UI also updates.
C++ side:
// Set the 'runtime' Context Property, this is my QQmlPropertyMap derived object
Runtime rt;
rt.GetData()->insert("abc", 120);
rt.GetData()->insert("xyz", 65);
view.rootContext()->setContextProperty("runtime", &rt);
QML side:
MyQmlObject
{
value: runtime.data.abc
}
This next part is where I’m getting stuck/confused.. I want to have a QML table that displays all the key/values in the property map and automatically updates. How do I go about this? I cant find any examples that use the QQmlPropertyMap as a model for a TableView or any other view.
TableView
{
anchors.fill: parent
model: runtime.model // ????
}
Surely there must be a simple way I’m not aware of? How can I use a QQmlPropertyMap as the model for the QML TableView?
Thanks
wysota
26th August 2013, 07:53
Why don't you just use a regular model instead of a property map?
sBoff
26th August 2013, 10:18
Hi wysota,
Thanks for your reply. Do you mean derive my own model object from say QAbstractTableModel or similar?
I originally started with QQmlPropertyMap as I need a way to easily map key/value pairs and to use this data to bind to QML objects - for that purpose QQmlPropertyMap seemed like the ideal choice. Maybe now that I am needing to display the data in a tableview that approach is no longer the best way?
Regards
wysota
26th August 2013, 10:28
Thanks for your reply. Do you mean derive my own model object from say QAbstractTableModel or similar?
More likely QAbstractListModel. But in general, yes.
I originally started with QQmlPropertyMap as I need a way to easily map key/value pairs and to use this data to bind to QML objects - for that purpose QQmlPropertyMap seemed like the ideal choice. Maybe now that I am needing to display the data in a tableview that approach is no longer the best way?
Maybe :)
sBoff
26th August 2013, 10:44
More likely QAbstractListModel. But in general, yes.
Thanks for your input :) - Ill try this out and post up if I have any issues with it. I had thought about doing this but I was sure there must have been an 'easy' way (it seems like a common use case to me?), but thankyou again; its nice to have another brain out there provide some clarity!
Regards
sBoff
26th August 2013, 23:48
It looks like I've come full circle. :)
I originally started this project a long time ago but then with my daughters birth had put things on hold. I'm now managing to scrape some time here and there so thought I would start it up again.
wysota, I've now created a QAbstractListModel derived object which stores my data in an internal QVector. This is working beautifully in the QML side and I have a TableView that shows all entries and updates correctly when the internal data updates.
class DataEngine : public QAbstractListModel
{
private:
QVector<Data> m_Data;
};
This leads me onto the second issue which was what I originally faced so long ago - Data is added to my 'data engine' dynamically at runtime, I dont know prior to runtime what data will be available. I need to be able to bind a QML object's value to a data entry and have the QML object also update when the data changes.
MyQmlObject
{
value: runtime.abc // <-- abc is a dynamic, we dont know until runtime that there is a property called abc
}
As far as I'm aware there is no mechanism exposed in Qt to allow for dynamic properties (other than using QQmlPropertyMap, QQmlListProperty etc)? If this is correct do I go about binding a UI element's value to a data entry? I guess I could always use a Q_INVOKABLE member to return the data however, how would I then get the QML object to upadte when the value has changed?
I'm currently thinking I'll have to use a QQmlListProperty as my internal data storage for my QAbstractListModel derived object. The problem is this leads back to the original issue - I now have to either:
- Make sure a data entry can only ever be modified through the QAbstractListModel derived object (to keep the update notifications of QAbstractListModel and the QQmlPropertyList in sync)
OR
- Find a way to detect a change in a data entry and inform the QAbstractListModel that it also needs to update.
I hope that makes sense? Any thoughts/suggestions?
wysota
27th August 2013, 07:40
how would I then get the QML object to upadte when the value has changed?
Bind the object's property to a function call that will return the data or invoke some imperative code when contents of the model change.
I'm currently thinking I'll have to use a QQmlListProperty as my internal data storage for my QAbstractListModel derived object.
No, that's not a good idea.
- Make sure a data entry can only ever be modified through the QAbstractListModel derived object
That's always the proper approach.
sBoff
27th August 2013, 10:33
Bind the object's property to a function call that will return the data or invoke some imperative code when contents of the model change.
This is fine, I have the QML object's property bound to the a function (I can see it hitting the breakpoint where I return a value) however, this only gets called once while the QML object is loading. From that point on, it never updates despite the data changing (this the issue QQmlPropertyMap and the likes resolved). I guess the question then boils down to, how can I update the QML object when I know data that it references has been updated?
Edit: I've had a bit of a play with this and the only solution I can come up with is binding the QML object's value a C++ object's property and provide a NOTIFY signal
C++:
class Runtime : public QObject
{
Q_OBJECT
Q_PROPERTY(RuntimeData* data READ GetData NOTIFY modelChanged)
public:
The RuntimeData object is my QAbstractListModel derived object. In this object I've then created a Q_INVOKABLE member that retuns the data value base on an index (for now).
class RuntimeData : public QAbstractListModel
{
Q_OBJECT
public:
Q_INVOKABLE int GetData(int index)
{
if (index >= 0 && index < m_Data.count())
return m_Data[index].Value().toInt();
return 0;
}
Finally, its all working but there is a remaining issue. With this implementaion, anytime I have to update any data, I also have to emit the modelChanged signal to inform the QML to update. Hypothetically if I have 1000 data entries and 1000 QML objects bound to these, if one data item changes all QML objects will update.
Again, I feel like I must be missing something? Why is this so complicated?
Powered by vBulletin® Version 4.2.5 Copyright © 2024 vBulletin Solutions Inc. All rights reserved.