PDA

View Full Version : Most efficient way to implement data in QML from C++



sam_s
3rd November 2016, 23:59
QUESTION: Given the platform and amount of data - what is the best method for populating model in QML that allows for the usage of delegates

I spent a couple of days researching this but have not found an answer to this.
BACKGROUND:

I'm starting a Qt project that will use three primary tables (each table has approx 23 rows, 10 columns - approx 230 data points for each table (~750 data points total).

Need direction on the best possible way to build and update these tables in c++ while allowing the usage of delegates in QML

The tables will NOT grow or shrink in size at run time (i.e. add or remove rows or columns ) but the data will be updated so any values that are painted on the screen must be updated

The 800 values (spanning 3 tables) are currently stored and manipulated in a seperate C files that uses static arrays with "get" and "set" functions

The two ways we are currently looking at are:
a) creating a list model in QML and populating data with javascript (see code example below
This method is working but we are concerned about performance issues using javascript over c++
QUESTION: Is this the best method?

b) creating a QAbstractTableModel in c++
new to this concept and am concerned that I will have to create individual get / set functions for each column. We currently have over 50 columns. (I believe these are "roles" within the QAbstractmodel )
QUESTION: Does QAbstractTableModel allow for the usage of delegates in QML, If using QAbstractmodel is the best approach, then does every column need it's own get set function?


QUESTION: Is there a third option that we are not considering?


Platform will be on an embedded system using the TI AM335 driving a 800x480 LCD (same as the beaglebone Black) and embedded linux

Here is an example of option A



//create instance of c++ class
CrcDataQML2{
id: crcClassInstance
}



//create List Model
ListModel{
id: crcPointListModel
}


function setIndividualValue(columnToSet, IndexToSet, valueToSet)
{
crcClassInstance.setDataQML(columnToSet, IndexToSet, valueToSet);
}


//function to populate values in ListModel
function getDataValues(id)
{
var i;
var j;
var k;
console.log()
for (i = 0; i<23; i++ )
{

id.set(i,{ "setPoint":crcClassInstance.getDataQML(Global.POINT_SET_POIN T,i),
"currentValue":crcClassInstance.getDataQML(Global.POINT_CURRENT_ VALUE,i),
"engineeringUnits":crcClassInstance.getDataQML(Global.POINT_ENGINEER ING_UNITS,i),
"resolution":crcClassInstance.getDataQML(Global.POINT_RESOLUTI ON,i),

name:crcClassInstance.getQMLDataString(Global.POIN T_NAME,i),
"currentValueSource":crcClassInstance.getDataQML(Global.POINT_CV_ORIGI N,i),
"setPointSource":crcClassInstance.getDataQML(Global.POINT_SP_ORIGI N,i),
"alarmHigh":crcClassInstance.getDataQML(Global.POINT_ALARM_OV ER,i),
"alarmLow":crcClassInstance.getDataQML(Global.POINT_ALARM_UN DER,i),
"alarmStatus":crcClassInstance.getDataQML(Global.POINT_ALARM_ST ATUS,i),
"displayPoint":crcClassInstance.getBoolDataQML(Global.POINT_DISP LAY,i),
"setPointDisplay":false,
"alarmSetup":3,
"currentValueOffset":crcClassInstance.getDataQML(Global.POINT_CURRENT_ VALUE_OFFSET,i)
});
}
}


Timer{
id: timerSam
running: true
repeat: true
triggeredOnStart: true
interval: 1000
onTriggered: {
//updates values in c++
//getDataValues(crcPointListModel);
testRowInsertion(crcPointListModel,"name");
//sets a value in c++ equal to the current secnd value - just to prove we are able to manipulate values in c++
setIndividualValue(Global.POINT_CURRENT_VALUE, 0, parseInt(Qt.formatTime(new Date(),"ss")) );

}
}

anda_skoa
4th November 2016, 10:57
QUESTION: Given the platform and amount of data - what is the best method for populating model in QML that allows for the usage of delegates

A custom C++ model.

The delegate part is on the QML side, it doesn't care what kind of model you have. Even a plain number can be treated as a model.



The two ways we are currently looking at are:
a) creating a list model in QML and populating data with javascript (see code example below
This method is working but we are concerned about performance issues using javascript over c++
QUESTION: Is this the best method?

No



b) creating a QAbstractTableModel in c++
new to this concept and am concerned that I will have to create individual get / set functions for each column. We currently have over 50 columns. (I believe these are "roles" within the QAbstractmodel )
QUESTION: Does QAbstractTableModel allow for the usage of delegates in QML, If using QAbstractmodel is the best approach, then does every column need it's own get set function?

While you can use QAbstractTableModel, e.g. if you also want to show the data in a widget based QTableView, QtQuick will only treat it as a list model.
A table model can still work if the model can map the QML roles onto columns, or you just derive from QAbstractListModel.



QUESTION: Is there a third option that we are not considering?

Yes, QAbstractListModel

Cheers,
_

sam_s
4th November 2016, 18:25
Thank you anda_skoa for your help and quick turn around

I'm still really new to Qt and can't find a decent example on how to populate the QAbstractTableModel with row and column data similar to how I was doing it in QML

In this QML code I was able to populate each row with the following code



ListModel{
id: crcPointListModel
}

function getDataValues(id)
{
var i;
var j;

for (i = 0; i<23; i++ )
{

id.set(i,{ "setPoint":crcClassInstance.getDataQML(Global.POINT_SET_POIN T,i),
"currentValue":crcClassInstance.getDataQML(Global.POINT_CURRENT_ VALUE,i),
"engineeringUnits":crcClassInstance.getDataQML(Global.POINT_ENGINEER ING_UNITS,i),
"resolution":crcClassInstance.getDataQML(Global.POINT_RESOLUTI ON,i),

name:crcClassInstance.getQMLDataString(Global.POIN T_NAME,i),
"currentValueSource":crcClassInstance.getDataQML(Global.POINT_CV_ORIGI N,i),
"setPointSource":crcClassInstance.getDataQML(Global.POINT_SP_ORIGI N,i),
"alarmHigh":crcClassInstance.getDataQML(Global.POINT_ALARM_OV ER,i),
"alarmLow":crcClassInstance.getDataQML(Global.POINT_ALARM_UN DER,i),
"alarmStatus":crcClassInstance.getDataQML(Global.POINT_ALARM_ST ATUS,i),
"displayPoint":crcClassInstance.getBoolDataQML(Global.POINT_DISP LAY,i),
"setPointDisplay":false,
"alarmSetup":3,
"currentValueOffset":crcClassInstance.getDataQML(Global.POINT_CURRENT_ VALUE_OFFSET,i)
});
}
}

Timer{
id: timerSam
running: true
repeat: true
triggeredOnStart: true
interval: 1000
onTriggered: {
//updates values in c++
getDataValues(crcPointListModel);
//sets a value in c++ equal to the current secnd value - just to prove we are able to manipulate values in c++ and see them within the QML delegate
setIndividualValue(Global.POINT_CURRENT_VALUE, 0, parseInt(Qt.formatTime(new Date(),"ss")) );

}
}


Here are my questions:
- Does the QAbstractListModel have its own built in model / container?
- If it doesn't have its own container - given the model that this would have to replace in the QML code above - what would be the best container? QVector <QObject> ?
- If using QAbstractmodel is the best approach, then does every column need it's own get set function or can I populate each row with column / data as I was able to above?

Any direction or examples would help out greatly.

Thank you again for your help!

anda_skoa
5th November 2016, 10:13
- Does the QAbstractListModel have its own built in model / container?

No, it is just an interface to the data.
Your implementation can hold the data or delegate to a class that holds the data.
Your "crcClassInstances" sounds like you already have the latter.



- If it doesn't have its own container - given the model that this would have to replace in the QML code above - what would be the best container? QVector <QObject> ?

QVector sounds good, but as the element type you can use any data specific class you want.
Again your code looks like you already have the data stored somewhere.



- If using QAbstractmodel is the best approach, then does every column need it's own get set function or can I populate each row with column / data as I was able to above?

No. All data is accessed through the model's data() function.
In QML each delegate just accesses its data by the role names for each data aspect/column.



Any direction or examples would help out greatly.

I found a couple by googling for "c++ models for QML":
http://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel-subclass
https://sailfishos.org/develop/tutorials/combining-c-with-qml/

Creating such a model is fairly easy
1) Create a class derived from QAbstractListModel
2) Add an enum for the data roles
3) Implement roleNames() to provide a mapping between these enum values and the role names to use on QML side
4) Implement rowCount() to return the number of rows you have data for
5) Implement data() to return the value for a given row (from the index argument) and role (from the role argument)

Cheers,
_