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?



  • @Dave_022 said in Variable to select textfield in QML:

    onDroValueChanged: lcdToUpdate.text = "DRO: " + droValue

    lcdToUpdate is not a QML TextField object. In fact, it is defined nowhere. If you think you are referring to the lcdToUpdate property of your ArduinoSerial type, then that wouldn't work either, because the property is a string.

    Furthermore,

    typeFromArduinoSerial.setLcdToUpdate(lcdupdate)

    lcdupdate is an id, while lcdToUpdate 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 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
    


  • 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...


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.