How to update a text value from C++ dynamic ..
-
Hello,
I am trying to update a Text value from C++, but the value does not change his value in the QML
code. Within the backend class the value is updated correctly.QML Definition
import QtQuick 2.7 import QtQuick.Controls 2.0 as QQ2 import "../Style" import name.backend 1.0 .. .. Text { id: txtLatitude anchors.horizontalCenter: parent.horizontalCenter text: qsTr("Longitude: ") + backend.Latitude font.pixelSize: UIStyle.fontSizeS font.italic: true color: UIStyle.colorQtGray3 onTextChanged: { txtLatitude.text = qsTr("Longitude: ") + backend.Latitude } }
Backend definition file
#include <QObject> #include <QString> #include <QGeoPositionInfo> class BackEnd : public QObject { Q_OBJECT Q_PROPERTY(QString Latitude READ Latitude NOTIFY LatitudeChanged) public: explicit BackEnd(QObject *parent = nullptr); void setPosition(QGeoPositionInfo); QString Latitude(void); signals: void LatitudeChanged(); private: QString m_Latitude; };
Class BackEnd CPP File
#include <QString> #include "backend.h" BackEnd::BackEnd(QObject *parent) : QObject(parent) { m_Latitude="--.----"; } QString BackEnd::Latitude(void) { return m_Latitude; } void BackEnd::setPosition(QGeoPositionInfo Info) { double dValue; dValue = Info.coordinate().latitude(); QString sValue = QString::number(dValue,'f',4); m_Latitude = sValue; emit LatitudeChanged(); }
But the value on the screen is always "Longitude: --.----".
The value in the BackEnd-Class m_Latitude is updated correctly.
The value "backend.Latitude" has always "--.----".The base code of my QML Application is starting with the sample "wearable" Sample from here
Where is my fault ?
Best regards and thanks for any help
R. -
Hello,
I am trying to update a Text value from C++, but the value does not change his value in the QML
code. Within the backend class the value is updated correctly.QML Definition
import QtQuick 2.7 import QtQuick.Controls 2.0 as QQ2 import "../Style" import name.backend 1.0 .. .. Text { id: txtLatitude anchors.horizontalCenter: parent.horizontalCenter text: qsTr("Longitude: ") + backend.Latitude font.pixelSize: UIStyle.fontSizeS font.italic: true color: UIStyle.colorQtGray3 onTextChanged: { txtLatitude.text = qsTr("Longitude: ") + backend.Latitude } }
Backend definition file
#include <QObject> #include <QString> #include <QGeoPositionInfo> class BackEnd : public QObject { Q_OBJECT Q_PROPERTY(QString Latitude READ Latitude NOTIFY LatitudeChanged) public: explicit BackEnd(QObject *parent = nullptr); void setPosition(QGeoPositionInfo); QString Latitude(void); signals: void LatitudeChanged(); private: QString m_Latitude; };
Class BackEnd CPP File
#include <QString> #include "backend.h" BackEnd::BackEnd(QObject *parent) : QObject(parent) { m_Latitude="--.----"; } QString BackEnd::Latitude(void) { return m_Latitude; } void BackEnd::setPosition(QGeoPositionInfo Info) { double dValue; dValue = Info.coordinate().latitude(); QString sValue = QString::number(dValue,'f',4); m_Latitude = sValue; emit LatitudeChanged(); }
But the value on the screen is always "Longitude: --.----".
The value in the BackEnd-Class m_Latitude is updated correctly.
The value "backend.Latitude" has always "--.----".The base code of my QML Application is starting with the sample "wearable" Sample from here
Where is my fault ?
Best regards and thanks for any help
R. -
Hi,
here is the code of my main.cpp
int main(int argc, char *argv[]) { //QTranslator translator; int Status=0; gpsread *m_gps; QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); qmlRegisterType<BackEnd>("name.backend", 1, 0, "BackEnd"); app.setOrganizationName(PROGRAM_NAME); QTextCodec::setCodecForLocale( QTextCodec::codecForName("UTF-8") ); QLocale::setDefault(QLocale::German); // TODO: Do it for all countrys QQuickStyle::setStyle(QStringLiteral("qrc:/qml/Style")); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/carclient.qml"))); tzset(); SensorBuffer = new SensorValueDatas(); // Create a Query Buffer ApplicationPath=app.applicationDirPath () + "/"; // we are running on mac or linux loadSystemSettings(); m_ProgramisRunning=true; m_gps= new gpsread(); DebugDiagnosis = new ProgrammDiagnosis(ApplicationPath); DebugDiagnosis->writelog(QObject::tr("carclient"),QObject::tr("Main"),QObject::tr("Info"),QObject::tr("Program startup")); QThread* Data_thread = new QThread; m_DataThread = new DataThread(&m_ProgramisRunning,SensorBuffer,DebugDiagnosis); // Create a thread for reading the unit datablocks m_DataThread->moveToThread(Data_thread); QObject::connect(Data_thread, SIGNAL (started()), m_DataThread, SLOT (run())); QThread* Sensor_thread = new QThread; m_SensorThread = new SensorThread(&m_ProgramisRunning,SensorBuffer,DebugDiagnosis); // Create a thread for reading the unit datablocks m_SensorThread->moveToThread(Sensor_thread); QObject::connect(Sensor_thread, SIGNAL (started()), m_SensorThread, SLOT (run())); Data_thread->start(); // Start the background tasks Sensor_thread->start(); Status=app.exec(); QThread::msleep(2000); // Wait a little bit m_ProgramisRunning=false; SensorBuffer->clear(); // clear the query Buffer delete SensorBuffer; SensorBuffer=NULL; delete m_SensorThread; delete m_DataThread; delete Data_thread; delete Sensor_thread; delete DebugDiagnosis; delete m_gps; return Status; }
Best regards
R. -
@Ritchie said in How to update a text value from C++ dynamic ..:
onTextChanged:
{
txtLatitude.text = qsTr("Longitude: ") + backend.Latitude
}Why do you do this ?
The previoustxtLatitude.text: qsTr("Longitude: ") + backend.Latitude
ought to be enough.
You break the binding by affecting a value imperatively totext
. -
Hi,
here is the code of my main.cpp
int main(int argc, char *argv[]) { //QTranslator translator; int Status=0; gpsread *m_gps; QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); qmlRegisterType<BackEnd>("name.backend", 1, 0, "BackEnd"); app.setOrganizationName(PROGRAM_NAME); QTextCodec::setCodecForLocale( QTextCodec::codecForName("UTF-8") ); QLocale::setDefault(QLocale::German); // TODO: Do it for all countrys QQuickStyle::setStyle(QStringLiteral("qrc:/qml/Style")); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/carclient.qml"))); tzset(); SensorBuffer = new SensorValueDatas(); // Create a Query Buffer ApplicationPath=app.applicationDirPath () + "/"; // we are running on mac or linux loadSystemSettings(); m_ProgramisRunning=true; m_gps= new gpsread(); DebugDiagnosis = new ProgrammDiagnosis(ApplicationPath); DebugDiagnosis->writelog(QObject::tr("carclient"),QObject::tr("Main"),QObject::tr("Info"),QObject::tr("Program startup")); QThread* Data_thread = new QThread; m_DataThread = new DataThread(&m_ProgramisRunning,SensorBuffer,DebugDiagnosis); // Create a thread for reading the unit datablocks m_DataThread->moveToThread(Data_thread); QObject::connect(Data_thread, SIGNAL (started()), m_DataThread, SLOT (run())); QThread* Sensor_thread = new QThread; m_SensorThread = new SensorThread(&m_ProgramisRunning,SensorBuffer,DebugDiagnosis); // Create a thread for reading the unit datablocks m_SensorThread->moveToThread(Sensor_thread); QObject::connect(Sensor_thread, SIGNAL (started()), m_SensorThread, SLOT (run())); Data_thread->start(); // Start the background tasks Sensor_thread->start(); Status=app.exec(); QThread::msleep(2000); // Wait a little bit m_ProgramisRunning=false; SensorBuffer->clear(); // clear the query Buffer delete SensorBuffer; SensorBuffer=NULL; delete m_SensorThread; delete m_DataThread; delete Data_thread; delete Sensor_thread; delete DebugDiagnosis; delete m_gps; return Status; }
Best regards
R.@Ritchie You made a classic and common mistake: you register the type which you don't need to do, nor do you need to import it. Instead you should create an object in C++ and use setContextProperty. Example taken from the docs:
QQmlEngine engine; QStringListModel modelData; QQmlContext *context = new QQmlContext(engine.rootContext()); context->setContextProperty("myModel", &modelData);
Then the object is available in QML as a global object.
-
Why do you do this ?
The previous txtLatitude.text: qsTr("Longitude: ") + backend.Latitude ought to be enough.
You break the binding by affecting a value imperatively to text.
I thought this needed to update the Text information, when the "function emit LatitudeChanged();"
will update the text information.
Its this not needed ?@Eeli K
I will take a closer look into it. Have to find out the correct meaning of these function.
Totally new for me. -
Why do you do this ?
The previous txtLatitude.text: qsTr("Longitude: ") + backend.Latitude ought to be enough.
You break the binding by affecting a value imperatively to text.
I thought this needed to update the Text information, when the "function emit LatitudeChanged();"
will update the text information.
Its this not needed ?@Eeli K
I will take a closer look into it. Have to find out the correct meaning of these function.
Totally new for me.@Ritchie You have:
text: qsTr("Longitude: ") + backend.Latitude //sic! should be "Latitude"?
If backend.Latitude is Q_PROPERTY and the change signal is emitted in C++ the 'text' property is updated automatically. That's the idea of property bindings in QML - you don't have to do it imperatively in javascript code.
-
@Eeli-K
You are right. I changed it toText { id: txtLatitude anchors.horizontalCenter: parent.horizontalCenter text: qsTr("Latitude: ") + BackEnd.Latitude font.pixelSize: UIStyle.fontSizeS font.italic: true color: UIStyle.colorQtGray3 }
I also add these line into the main function
BackEnd UserDisplay; ... ... QQmlEngine QMLEngine; QQmlContext *context = new QQmlContext(QMLEngine.rootContext()); context->setContextProperty("BackEnd", &UserDisplay);
But now I get an Compiler error for the last two lines.
Main.cpp:95: Fehler: invalid use of incomplete type ‘class QQmlContext’ QQmlContext *context = new QQmlContext(QMLEngine.rootContext());
and
invalid use of incomplete type ‘class QQmlContext’ context->setContextProperty("BackEnd", &UserDisplay);
But all the sample I saw in the Internet are using these two line.
Best regards
R. -
@Eeli-K
You are right. I changed it toText { id: txtLatitude anchors.horizontalCenter: parent.horizontalCenter text: qsTr("Latitude: ") + BackEnd.Latitude font.pixelSize: UIStyle.fontSizeS font.italic: true color: UIStyle.colorQtGray3 }
I also add these line into the main function
BackEnd UserDisplay; ... ... QQmlEngine QMLEngine; QQmlContext *context = new QQmlContext(QMLEngine.rootContext()); context->setContextProperty("BackEnd", &UserDisplay);
But now I get an Compiler error for the last two lines.
Main.cpp:95: Fehler: invalid use of incomplete type ‘class QQmlContext’ QQmlContext *context = new QQmlContext(QMLEngine.rootContext());
and
invalid use of incomplete type ‘class QQmlContext’ context->setContextProperty("BackEnd", &UserDisplay);
But all the sample I saw in the Internet are using these two line.
Best regards
R. -
@Eeli-K
You are right. That was the missing line.But now I get
qrc:/qml/GPS/GPSPage.qml:88: ReferenceError: BackEnd is not defined
Which is this line:
text: qsTr("Latitude: ") + BackEnd.Latitude
@Ritchie I don't know if this is the reason but QML expects type names to begin with uppercase and property names etc. to begin with lowercase. So try
context->setContextProperty("backend", &UserDisplay);
and backend.Latitude etc. in QML.
I recommend also sticking to Qt coding convention with C++ upper/lowercase: class names begin with upper case, property, function and object names begin with lowercase. It shouldn't be necessary, I think, but may save you or someone else from some headache when reading the code.
-
@Ritchie said in How to update a text value from C++ dynamic ..:
QQmlContext *context = new QQmlContext(QMLEngine.rootContext());
This is a reason. You are constructing a child context that no object has access to and you add your property into it.
Just add it to the rootContext of the engine you created in your main and where you loaded your qml file.
Additionally, you should set the context property before loading the qml file.