Variable to select textfield in QML
-
I am attempting to build on code that allows me to click a send button to send a value to Serial and then update the textfield associated with it with numbers returned. I can't work out how to control which text field is being updated without creating seperate instances for all of them?
arduinoserial.h
#include <QObject> #include <QSerialPort> class ArduinoSerial : public QObject { Q_OBJECT Q_PROPERTY(QString droValue READ droValue WRITE setDroValue NOTIFY droValueChanged) Q_PROPERTY(QString lcdToUpdate READ lcdToUpdate WRITE setLcdToUpdate NOTIFY lcdToUpdateChanged) public: ArduinoSerial(); QString droValue() const; QString lcdToUpdate() const; public slots: void startSerialPort(); // Starts the Open Serial Port Function void readSerial(); void setDroValue(const QString& value); void closeSerialPort(); void writeSerial(const QByteArray &data); void setLcdToUpdate(const QString &value); signals: void serialPortOpen(); // Signal for sucessfully opening Serial Port void serialPortEror(); // Signal on not finding arduino in openSerialPort void droValueChanged(); // Signal on data received from arduino void lcdToUpdateChanged(); // Signal on setting value for which lcd to use private: QSerialPort *arduino; static const quint16 arduino_uno_vendor_id = 9025; static const quint16 arduino_uno_product_id = 67; QString arduino_port_name; bool arduino_is_available; QString m_droValue; QString m_lcdToUpdate; void openSerialPort(); }; #endif // ARDUINOSERIAL_H
arduinoserial.cpp
#include "arduinoserial.h" #include <QDebug> #include <QSerialPort> #include <QSerialPortInfo> ArduinoSerial::ArduinoSerial() { } QString ArduinoSerial::droValue() const { return m_droValue; } QString ArduinoSerial::lcdToUpdate() const { return m_lcdToUpdate; qDebug() << lcdToUpdate(); } void ArduinoSerial::startSerialPort() { this->openSerialPort(); } void ArduinoSerial::readSerial() { // Read data static QByteArray byteArray; byteArray += arduino->readAll(); //we want to read all message not only chunks if(!QString(byteArray).contains("\n")) return; //sanitize data QString data = QString( byteArray ).remove("\r").remove("\n"); byteArray.clear(); // Print data qDebug() << "RECV: " << data; setDroValue(data); droValueChanged(); } void ArduinoSerial::setDroValue(const QString& value) { if (m_droValue != value) { m_droValue = value; droValueChanged(); } } void ArduinoSerial::closeSerialPort() { if(arduino->isOpen()){ arduino->close(); } qDebug() << "Seriol Port is closed"; } void ArduinoSerial::writeSerial(const QByteArray &data) { arduino->write(data); qDebug() << (data) + " written to serial"; } void ArduinoSerial::setLcdToUpdate(const QString &value) { if(m_lcdToUpdate !=value) { m_lcdToUpdate = value; lcdToUpdateChanged(); qDebug() << m_lcdToUpdate; } } void ArduinoSerial::openSerialPort() { /* * Identify the port the arduino uno is on. */ arduino = new QSerialPort; arduino_is_available = false; arduino_port_name = ""; // // For each available serial port foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){ // check if the serialport has both a product identifier and a vendor identifier if(serialPortInfo.hasProductIdentifier() && serialPortInfo.hasVendorIdentifier()){ // check if the product ID and the vendor ID match those of the arduino uno if((serialPortInfo.productIdentifier() == arduino_uno_product_id) && (serialPortInfo.vendorIdentifier() == arduino_uno_vendor_id)){ arduino_is_available = true; // arduino uno is available on this port arduino_port_name = serialPortInfo.portName(); qDebug() << QString("Arduino Port Name: %1").arg(arduino_port_name); } } } /* * Open and configure the arduino port if available */ if(arduino_is_available){ qDebug() << "Found the arduino port...\n"; arduino->setPortName(arduino_port_name); arduino->setBaudRate(QSerialPort::Baud9600); arduino->setDataBits(QSerialPort::Data8); arduino->setFlowControl(QSerialPort::NoFlowControl); arduino->setParity(QSerialPort::NoParity); arduino->setStopBits(QSerialPort::OneStop); arduino->open(QSerialPort::ReadWrite); qDebug() << arduino->isOpen(); QObject::connect(arduino, SIGNAL(readyRead()), this, SLOT(readSerial())); serialPortOpen(); }else{ serialPortEror(); } }
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "arduinoserial.h" int main(int argc, char *argv[]) { qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard")); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; qmlRegisterType<ArduinoSerial>("arduino.serial", 1, 0, "ArduinoSerial"); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
main.qml
import QtQuick 2.11 import QtQuick.Window 2.11 import QtQuick.VirtualKeyboard 2.3 import QtQuick.Controls 2.2 import arduino.serial 1.0 import QtQuick.Dialogs 1.2 Window { id: window visible: true width: 800 height: 400 title: qsTr("Serial Port") MessageDialog { id: serialErrorDialog title: "Serial Port Error" icon: "Critical" informativeText: "Can't find arduino!" standardButtons: StandardButton.Ok modality: Qt.ApplicationModal onAccepted: Qt.quit(); } ArduinoSerial { id: typeFromArduinoSerial onSerialPortOpen: console.log("Serial Port Open") onSerialPortEror: serialErrorDialog.visible = true onDroValueChanged: lcdToUpdate.text = "DRO: " + droValue } Column{ spacing: 50 Row{ Button { id: serialstartbutton text: "Open Serial Port" onClicked: { typeFromArduinoSerial.startSerialPort() typeFromArduinoSerial.setLcdToUpdate(lcdupdate) } } TextField { id: lcdupdate text: "" } } Row{ Button { id: writeSerial1 text: "Write 20 to Serial" onClicked: { typeFromArduinoSerial.writeSerial("start 20 \r") typeFromArduinoSerial.setLcdToUpdate(lcdupdate1) } } TextField { id: lcdupdate1 text: "" } } Row { Button { id: writeSerial2 text: "Write 50 to Serial" onClicked: { typeFromArduinoSerial.writeSerial("start 50 \r") } } TextField { id: lcdupdate2 text: "" } } Row{ Button { id: closeSerial text: "Close Serial Port" onClicked: { typeFromArduinoSerial.closeSerialPort() } } } } }
Currently this runs but does not update any textfield?
-
I am attempting to build on code that allows me to click a send button to send a value to Serial and then update the textfield associated with it with numbers returned. I can't work out how to control which text field is being updated without creating seperate instances for all of them?
arduinoserial.h
#include <QObject> #include <QSerialPort> class ArduinoSerial : public QObject { Q_OBJECT Q_PROPERTY(QString droValue READ droValue WRITE setDroValue NOTIFY droValueChanged) Q_PROPERTY(QString lcdToUpdate READ lcdToUpdate WRITE setLcdToUpdate NOTIFY lcdToUpdateChanged) public: ArduinoSerial(); QString droValue() const; QString lcdToUpdate() const; public slots: void startSerialPort(); // Starts the Open Serial Port Function void readSerial(); void setDroValue(const QString& value); void closeSerialPort(); void writeSerial(const QByteArray &data); void setLcdToUpdate(const QString &value); signals: void serialPortOpen(); // Signal for sucessfully opening Serial Port void serialPortEror(); // Signal on not finding arduino in openSerialPort void droValueChanged(); // Signal on data received from arduino void lcdToUpdateChanged(); // Signal on setting value for which lcd to use private: QSerialPort *arduino; static const quint16 arduino_uno_vendor_id = 9025; static const quint16 arduino_uno_product_id = 67; QString arduino_port_name; bool arduino_is_available; QString m_droValue; QString m_lcdToUpdate; void openSerialPort(); }; #endif // ARDUINOSERIAL_H
arduinoserial.cpp
#include "arduinoserial.h" #include <QDebug> #include <QSerialPort> #include <QSerialPortInfo> ArduinoSerial::ArduinoSerial() { } QString ArduinoSerial::droValue() const { return m_droValue; } QString ArduinoSerial::lcdToUpdate() const { return m_lcdToUpdate; qDebug() << lcdToUpdate(); } void ArduinoSerial::startSerialPort() { this->openSerialPort(); } void ArduinoSerial::readSerial() { // Read data static QByteArray byteArray; byteArray += arduino->readAll(); //we want to read all message not only chunks if(!QString(byteArray).contains("\n")) return; //sanitize data QString data = QString( byteArray ).remove("\r").remove("\n"); byteArray.clear(); // Print data qDebug() << "RECV: " << data; setDroValue(data); droValueChanged(); } void ArduinoSerial::setDroValue(const QString& value) { if (m_droValue != value) { m_droValue = value; droValueChanged(); } } void ArduinoSerial::closeSerialPort() { if(arduino->isOpen()){ arduino->close(); } qDebug() << "Seriol Port is closed"; } void ArduinoSerial::writeSerial(const QByteArray &data) { arduino->write(data); qDebug() << (data) + " written to serial"; } void ArduinoSerial::setLcdToUpdate(const QString &value) { if(m_lcdToUpdate !=value) { m_lcdToUpdate = value; lcdToUpdateChanged(); qDebug() << m_lcdToUpdate; } } void ArduinoSerial::openSerialPort() { /* * Identify the port the arduino uno is on. */ arduino = new QSerialPort; arduino_is_available = false; arduino_port_name = ""; // // For each available serial port foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){ // check if the serialport has both a product identifier and a vendor identifier if(serialPortInfo.hasProductIdentifier() && serialPortInfo.hasVendorIdentifier()){ // check if the product ID and the vendor ID match those of the arduino uno if((serialPortInfo.productIdentifier() == arduino_uno_product_id) && (serialPortInfo.vendorIdentifier() == arduino_uno_vendor_id)){ arduino_is_available = true; // arduino uno is available on this port arduino_port_name = serialPortInfo.portName(); qDebug() << QString("Arduino Port Name: %1").arg(arduino_port_name); } } } /* * Open and configure the arduino port if available */ if(arduino_is_available){ qDebug() << "Found the arduino port...\n"; arduino->setPortName(arduino_port_name); arduino->setBaudRate(QSerialPort::Baud9600); arduino->setDataBits(QSerialPort::Data8); arduino->setFlowControl(QSerialPort::NoFlowControl); arduino->setParity(QSerialPort::NoParity); arduino->setStopBits(QSerialPort::OneStop); arduino->open(QSerialPort::ReadWrite); qDebug() << arduino->isOpen(); QObject::connect(arduino, SIGNAL(readyRead()), this, SLOT(readSerial())); serialPortOpen(); }else{ serialPortEror(); } }
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "arduinoserial.h" int main(int argc, char *argv[]) { qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard")); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; qmlRegisterType<ArduinoSerial>("arduino.serial", 1, 0, "ArduinoSerial"); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
main.qml
import QtQuick 2.11 import QtQuick.Window 2.11 import QtQuick.VirtualKeyboard 2.3 import QtQuick.Controls 2.2 import arduino.serial 1.0 import QtQuick.Dialogs 1.2 Window { id: window visible: true width: 800 height: 400 title: qsTr("Serial Port") MessageDialog { id: serialErrorDialog title: "Serial Port Error" icon: "Critical" informativeText: "Can't find arduino!" standardButtons: StandardButton.Ok modality: Qt.ApplicationModal onAccepted: Qt.quit(); } ArduinoSerial { id: typeFromArduinoSerial onSerialPortOpen: console.log("Serial Port Open") onSerialPortEror: serialErrorDialog.visible = true onDroValueChanged: lcdToUpdate.text = "DRO: " + droValue } Column{ spacing: 50 Row{ Button { id: serialstartbutton text: "Open Serial Port" onClicked: { typeFromArduinoSerial.startSerialPort() typeFromArduinoSerial.setLcdToUpdate(lcdupdate) } } TextField { id: lcdupdate text: "" } } Row{ Button { id: writeSerial1 text: "Write 20 to Serial" onClicked: { typeFromArduinoSerial.writeSerial("start 20 \r") typeFromArduinoSerial.setLcdToUpdate(lcdupdate1) } } TextField { id: lcdupdate1 text: "" } } Row { Button { id: writeSerial2 text: "Write 50 to Serial" onClicked: { typeFromArduinoSerial.writeSerial("start 50 \r") } } TextField { id: lcdupdate2 text: "" } } Row{ Button { id: closeSerial text: "Close Serial Port" onClicked: { typeFromArduinoSerial.closeSerialPort() } } } } }
Currently this runs but does not update any textfield?
@Dave_022 said in Variable to select textfield in QML:
onDroValueChanged: lcdToUpdate.text = "DRO: " + droValue
lcdToUpdate
is not a QMLTextField
object. In fact, it is defined nowhere. If you think you are referring to thelcdToUpdate
property of yourArduinoSerial
type, then that wouldn't work either, because the property is a string.Furthermore,
typeFromArduinoSerial.setLcdToUpdate(lcdupdate)
lcdupdate
is an id, whilelcdToUpdate
is a string property.When defining a custom QML type as you did, you are not supposed to access the properties with their setXXX function etc in QML: just do it as you would do with any other QML type:
typeFromArduinoSerial.lcdToUpdate: myStringVar //when binding typeFromArduinoSerial.lcdToUpdate = myStringVar //when assigning in JS
and vice versa.
In your example you must use something like:
typeFromArduinoSerial.lcdToUpdate = "LCD1"
and
onDroValueChanged: { if (lcdToUpdate ==="LCD1") lcdtoupdate1.text = "DRO: " + droValue else lcdtoupdate2.text = "DRO: " + droValue }
or something like that.
Finally, why don't you keep track of which LCD to update within QML only. This allows you to avoid having to define the
lcdToUpdate
property in yourArduinoSerial
type whilst allowing you to do something like this:Window { property TextField lcdToUpdate: lcdtoupdate1 //default Button { id: writeSerial1 text: "Write 20 to Serial" onClicked: { typeFromArduinoSerial.writeSerial("start 20 \r") LcdToUpdate = lcdupdate1 //LcdToUpdate is essentially a reference to lcdupdate1 } } }
Idem for the 2nd button.
And then, you can use your original code:
onDroValueChanged: LcdToUpdate.text = "DRO: " + droValue
-
Re: Variable to select textfield in QML
/Finally, why don't you keep track of which LCD to update within QML only. This allows you to avoid having to define the lcdToUpdate property in your ArduinoSerial type whilst allowing you to do something like this: Window { property TextField lcdToUpdate: lcdtoupdate1 //default Button { id: writeSerial1 text: "Write 20 to Serial" onClicked: { typeFromArduinoSerial.writeSerial("start 20 \r") LcdToUpdate = lcdupdate1 //LcdToUpdate is essentially a reference to lcdupdate1 } } } Idem for the 2nd button. And then, you can use your original code: onDroValueChanged: LcdToUpdate.text = "DRO: " + droValue
Thank you; I attempted this myself prior to the code I posted and failed miserably. This has worked for me. Onwards and upwards...
-
Re: Variable to select textfield in QML
/Finally, why don't you keep track of which LCD to update within QML only. This allows you to avoid having to define the lcdToUpdate property in your ArduinoSerial type whilst allowing you to do something like this: Window { property TextField lcdToUpdate: lcdtoupdate1 //default Button { id: writeSerial1 text: "Write 20 to Serial" onClicked: { typeFromArduinoSerial.writeSerial("start 20 \r") LcdToUpdate = lcdupdate1 //LcdToUpdate is essentially a reference to lcdupdate1 } } } Idem for the 2nd button. And then, you can use your original code: onDroValueChanged: LcdToUpdate.text = "DRO: " + droValue
Thank you; I attempted this myself prior to the code I posted and failed miserably. This has worked for me. Onwards and upwards...
@Dave_022 said in Variable to select textfield in QML:
This has worked for me. Onwards and upwards.
Cheers!
Also, don't forget to mark this post as solved...