Connecting C++ with QML
-
Because this is my first experience in QML and I never used JavaScript as well to write additional code in QML but I feel confident in c++.
I have two dozens of TextField objects to accept user input in different ways with input validation. It might be string, integer or double that`s why I use the most simple approach for my current level of knowledge.I have a window with 7 TextFields and single Input button. How do I parse them?
//QML Button{ id: inputWindow1Button objectName: "inputWindow1Button" text: qsTr("Input") //LOGIC onClicked: { //emits signal to run Controller::window1TextFieldsParser() which is declared as Q_INVOKABLE Controller.window1TextFieldsParser() } }
.cpp
void Controller::window1TextFieldsParser(){ QQuickWindow* multiWindow = m_currentWindow; //currently active window where cpp looks for objectName to parse QObject* speed = multiWindow->findChild<QObject*>("speed1of3"); //look for QML objectName QString speedText = speed->property("text").toString().trimmed(); //extract text from "speed1of3" TextField QML object double speedCheck; if (speedText.isEmpty()){//check if QString is empty //Error signal to QML emit showInfo(tr("Speed field is empty"), tr("Invalid input"), m_currentWindow); return; }else{ //convert QString to double, normalize input (treat both coma and dot as decimal separator) speedCheck = convertStringToDouble(speedText); } //validate input range if(speedCheck<=0 || std::isnan(speedCheck)){ //handle invalid input through emit showInfo() return; }else{ m_speed=speedCheck; //assign member variable with valid value } }
-
wrote 14 days ago last edited by
Thanks to your recommendations I rejected the ugly practice to dig out input values from QML with findChild<QObject*>("objectName"); and implemented a Q_PROPERTY binding.
I see a disappointing limitation, maybe you can give me an advise how to overcome it
Consider the simple example with several TextFields, Input button and Start button
QML Button{ id: inputButton onClicked:{ //extract values from TextFieldName.text AppController.setTextFieldValue([value1, value2,...]) } Button{ id: startButton onClicked:{ AppController.startCalculations() }
I have connected my QML and cpp as follows
cpp Q_PROPERTY (QVariantList someValues READ someValues WRITE setSomeValues NOTIFY someValuesChanged FINAL) As soon as user pushes Input button cpp receives and processes data because QML sends them through Q_INVOKABLE void setSomeValues() like this: void ControllerClass::setSomeValues(const QVariantList &someValues){ m_temperature = someValues[0]; //and so on ... m_windSpeed = someValues[5]; }
Let`s image the situation that user has provided input but forgotten to push Input button
Cpp has not received data yet but those values exist in QML TextFieldsvoid ControllerClass::startCalculation(){ if(!temperature.hasValue()){ //std:optional<int> //Instead of request QML for current values requestQML(); //user has forgotten to push button to set temp //I need to emit error message emit showInfo("Error", "Invalid input"); return; }
So the limitation I see in this case that QML can send data to cpp, but cpp cannot request current values.
How cpp can ask QML for missing data? How to handle such cases properly? -
wrote 14 days ago last edited by
You could have a C++ object exposed as a QML object that exposes properties corresponding to each data field. You can then bind the QML fields directly to the C++ properties and the C++ is always up to date with what is in the QML.
-
wrote 14 days ago last edited by
Do you mean no Input button and expose every TextField as separate Q_PROPERTY through onEditingFinished:?
-
That depends on what you specify for your UX. If you don't want to have to use a submit button then mapping each textfield to a c++ property is the more direct way yes. Doing that on
editingFinished
is a good solution.
21/25