get single item and it's property of QAbstractListModel in QML
-
Hello,
I have a c++ class derived from QAbstractListModel which I use as my Datamodel for QML.
It has hundrets of objects in it which I want to access directly in QML.
Using the whole model e.g. in a list ist working.ListView { width: 100; height: 800 model: dataSourceModelObject delegate: Text { text: name + " " + value} } Component { id: mydelegate Text { text: model.name + model.value } }
But I want to access a property of a single object in this model.
How can this be done?regards
-
Can you derive all your Objects from a QObject that you've enhanced with a getter? You should be able to even write a getter that takes the property's name, like that (untested):
Q_INVOKABLE QVariant MyModelObject::getVariantProperty(const char* propName) { return(this->property(propName); }
Maybe the Smart Data Models by Thomas Boutroue could help you, too. I am using them in a project.
-
@Slash200
you can write a custom method such as:Q_INVOKABLE QVariantMap MyModel::get(int index) const { QVariantMap data; const QModelIndex idx = this->index(i,0); if( !index.isValid() ) return data; const QHash<int,QByteArray> rn = this->roleNames(); QHashIterator<int,QByteArray> it(rn); while (it.hasNext()) data[it.value()] = index.data(it.key()); return data; }
This method returns a JS object containing all the data for the given row, using the role names you would also use in the delegate to access the data.
Usage in QML:
dataSourceModelObject.get(row).name
-
@raven-worx Thank you for you reply! This is what I'm looking for, but I have a problem with implementing this function.
I tried this:QVariantMap datasourcemodel::get(int row) const { QHash<int, QByteArray> names = roleNames(); QHashIterator<int, QByteArray> i(names); QVariantMap res; QModelIndex idx = index(row, 0); while(i.hasNext()) { i.next(); QVariant data = idx.data(i.key()); res[i.value()] = data; } qDebug() << res; return res; }
Then I tried to show a value in QML but it shows only the values on start. Its not updating
Text { id: text2 x: 600 y: 137 width: 100 height: 31 text: dataSourceModelObject.get(cbx_sources.currentIndex).value font.pixelSize: 12 }
-
When you send the QVariantMap, you are sending the key, value pairs. You are not sending the original object which changes. If you want to handle the changes in QML, expose the entire object itself e.g
TestObject* MyModel::get(int index) {
// get the object using index
// return the object
}Please note that TestObject need to know to QML using qmlRegisterMetaType<>()..
-
@dheerendra
Thank you so much dheerendra.
I'm still have to learn so much about programming.
Can you be so nice and show me how I can return the object itself from the get function in the model?regards
Bastian -
Did u write a get method the way I described ? Can u tell me what type object your model contains ?
-
@dheerendra I tried to implent the get function, but i dont understand how to return a reference of the object.
This is the object inside the model:Header:
#ifndef DATASOURCEOBJECT_H #define DATASOURCEOBJECT_H #include <QObject> class DataSourceObject { public: //Constructors and destructors DataSourceObject(const int &id, const QString &name, const QString &displayname, const double &value); int id() const; void setid(const int &id); QString name() const; void setname(const QString &name); QString displayname() const; void setdisplayname(const QString &displayname); double value() const; void setvalue(const double &value); private: int m_id; QString m_name; QString m_displayname; double m_value; }; #endif // DATASOURCEOBJECT_H
cpp:
#include "datasourceobject.h" DataSourceObject::DataSourceObject(const int &id, const QString &name, const QString &displayname, const double &value) : m_id(id), m_name(name), m_displayname(displayname), m_value(value) { } int DataSourceObject::id() const { return m_id; } void DataSourceObject::setid(const int &id) { if (id != m_id) { m_id = id; //emit idChanged(); } } QString DataSourceObject::name() const { return m_name; } void DataSourceObject::setname(const QString &name) { if (name != m_name) { m_name = name; //emit nameChanged(); } } QString DataSourceObject::displayname() const { return m_displayname; } void DataSourceObject::setdisplayname(const QString &displayname) { if (displayname != m_displayname) { m_displayname = displayname; //emit displaynameChanged(); } } double DataSourceObject::value() const { return m_value; } void DataSourceObject::setvalue(const double &value) { //if(value != m_value) { m_value = value; //emit valueChanged(); //} }
-
How are storing the data objects in model ? Is it list or some other containers ? Also ur data object shud inherit from qobject
-
@dheerendra I read a JSON file an then i store the data in the model:
void Connect::initDataSources(){ QString jsonFileValue; //value of jasonfile, extracted as QString //Some file opening logics here, including existence and reading test QFile datasourcesjson(QStringLiteral("datasources.json")); //open document in read mode datasourcesjson.open((QIODevice::ReadOnly)); //read whole data from json file in a Qstring if(!datasourcesjson.isReadable()){ qWarning("datasources.json not readable.\n\n\n"); return; } else { jsonFileValue = datasourcesjson.readAll(); datasourcesjson.close(); QJsonDocument m_DataSourceDocument = QJsonDocument::fromJson(jsonFileValue.toUtf8()); QJsonObject m_DataSourceObject = m_DataSourceDocument.object(); m_DataSourceArray = m_DataSourceObject.value(QString("datasources")).toArray(); //create for each Datasource a Instance of DataSourceObject for (const auto obj : m_DataSourceArray){ m_DataSourceModel.addDataSourceObject(DataSourceObject(obj.toObject().value("id").toInt(), obj.toObject().value("name").toString(), obj.toObject().value("displayname").toString(), 0)); } return; } }
-
DataSourceObject shud inherit from qobject. Also when you call adddatasource how object is stored inside the model ? Are u using qlist?
-
@dheerendra i tried to get it to work with Qobject but it didnt worked. Also the Example from Qt (called abstractidemmodel bundelt with qt creator) didnt inhert from qobject.
void datasourcemodel::addDataSourceObject(const DataSourceObject &DataSourceObject){ beginInsertRows(QModelIndex(), rowCount(), rowCount()); m_DataSourceObjects << DataSourceObject; endInsertRows(); }
-
m_DataSourceObjects
What is the datatype of above variable ? Can you show me the declaration ?
-
shouldn't be single items accessible with the data() function.
using the model in a listview works perfectly. But wenn access the value from a item directly in QML with this:
Text { id: text2 x: 600 y: 137 width: 100 height: 31 text: dataSourceModel.data(88,259) font.pixelSize: 12 }
Where 88 is the desired index and 259 the valueRole
qml returns: Unable to assign [undefined] to QString
this is my data function in my derived qabstractlistmodel class:
QVariant datasourcemodel::data(const QModelIndex & index, int role) const{ if(index.row() < 0 || index.row() >= m_DataSourceObjects.count()) return QVariant(); const DataSourceObject &dataSourceObject = m_DataSourceObjects[index.row()]; if (role == idRole) return dataSourceObject.id(); else if (role == nameRole) return dataSourceObject.name(); else if (role == displaynameRole) return dataSourceObject.displayname(); else if (role == valueRole) return dataSourceObject.value(); //else if (role == allRole) // return get(index.row()); return QVariant(); }
-
-
You have model
-
This model contains the list of DataSource Object.
-
You got the values using QVariantList
-
Now you asked the question saying that value does not change when value is changed in the backend.
-
If you are working with View & Model, any change in model will reflect in view provided your model has appropriate signal.
-
What you wanted is access single value in model data & display it. Display is not ListView etc.
-
Whenever you change the value in Backend, it should change in UI also.
e.g
Text { text : dataModel.dataSourceObj.value }
This is how you wanted access it. If any change in the value should also change. data() method will be called through view. What data() method returns is only a value. Whenever any value changes, how it will reflect in your text UI ? So data(..) method will not of use.
You are trying to use model like object which gives the value.
So I suggested you to have method like following.Assuming that you store the object in the QList
TestObject* MyModel::get(int index) { DataSourceObj *obj = list.at(index) return obj }
I kept on asking show me how you store the DataSourceObj in model. Apart from this answer I get something else. Hence I was not able to give you get function details. Now I assumed you are storing as QList<> I have shown you the method signature.
I have requested you to inherit from QObject also. The reason is that property binding has to work with signal/slots. There is a way to do without QObject and use Q_GADGET. However this does not work for signal/slots.Hope things are clarified. Again I'm asking show me how do you store DataSource objects in Model. Which datastructure are you using to store DataSource Objects ?. If your problem is not the way I explained, then you are looking for something else & I did not understand your problem.
-
-
Apologies for the communication problems.
To simplify the whole thing I uploaded the project to github.There you see also the main.qml where i try the get the value of a object depending on the selected item with the combobox
-
no in the main.qml
Text { id: text2 x: 600 y: 137 width: 100 height: 31 //text: dataSourceModel.get(cbx_sources.currentIndex).value text: dataSourceModel.data(cbx_sources.currentIndex,259) font.pixelSize: 12 }
i want to give the text2 the value of the selected item from combobox cbx_sources.