PDA

View Full Version : Q_PROPERTY, Q_INVOKABLE, signals and data exchange between C++ and QML



DLabonte
13th July 2018, 16:03
Good morning,

My application contains different screens (using QML Tab and TabView) that are navigated in response to operator actions.

The C++ portion of the code contains the following declarations (in header file)


Q_PROPERTY(QVariantMap recordingStats READ getRecordingStats NOTIFY recordingStatsChanged)
...
Q_INVOKABLE QString getSensorLabel( int sensorIndex);

Q_INVOKABLE int getHeartBeatCount( int channel);

A std::map<int, int> variable is also declared, with the value part initialized to non-zero for debugging purposes. Its content is modified in the same method where the recordingStats property is changed. The signal recordingStatsChanged is then emitted.

In QML, the following properties and Connections are declared:

Item {
id: recordScreen

property int heartBeatCountCh0 : 0
property int heartBeatCountCh1 : 0
property int heartBeatCountCh2 : 0
...
Connections {
target: Helper
onRecordingStatsChanged:
{
console.log( "onRecordingStatsChanged(), heart beat count at 1: ", Helper.getHeartBeatCount( 1))
recordScreen.heartBeatCountCh0 = Helper.getHeartBeatCount( 0)
recordScreen.heartBeatCountCh1 = Helper.getHeartBeatCount( 1)
recordScreen.heartBeatCountCh2 = Helper.getHeartBeatCount( 2)
}
}

The recordingStats values are displayed correctly in the QML dialog. This has been working for some time, the exchange of data between C++ and QML using QVariantMap being well documented. The method getHeartBeatCount( int) is called in 2 different settings. In the method onRecordingStatsChanged above, but also when assigned the value to QML Textelement as shown here:


Text { // Correct (updated) value is displayed
...
text: recordScreen.heartBeatCountCh0
}

Text { // Error: Initial value is displayed ???
...
text: Helper.getHeartBeatCount( 3)
}

Could someone please explain why the call to Helper.getHeartBeatCount( 3) always returns the initial value assigned in C++? Note that the Tab containing the code above is visible when the command emit onRecordingStatsChanged() is executed.

The same approach is used elsewhere in the code, where an array is initialized well before the corresponding Tab where the values are shown is made visible. The correct values are displayed.

It appears to me that this is a synchronization/timing issue where the code inside onRecordingStatsChanged is always handled by the GUI thread whereas the calls to Helper.getHeartBeatCount( 3) is only handled when the Tab is initially made visible. It this the case? Any work around?

I tried to declare a Q_PROPERTY( QMap<int, int> ...) but was unable to get the code to work. I came across the following comment (from http://doc.qt.io/qt-5/properties.html)

For historical reasons, QMap and QList as property types are synonym of QVariantMap and QVariantList.
which means that the key is a QString instead of an int.

Thanks,
Daniel