qtqmluartqlistqiodevice

How to get 2D array from UART to QList<QString> Qt and set text on QML


I receive a 2D array from UART that sent from Arduino. I can show it in debug, but I can not save it in a QList variant to set text for matrix of rectangle in QML.

I want to show text on QML each rectangle.

How I can do?

This is Arduino code. I send 2d array 17x17

void setup(){
    pinMode(LED_BUILTIN,OUTPUT);
    analogWrite(LED_BUILTIN,255);
    Serial.begin(115200);
void loop(){
    double data[17][17];
    if(Serial.available()){
        delay(100);
        for(int i=0; i<17; i++){
            for(int j=0; j<17; j++){
                data[i][j] = i+j+0.01;
                sendData(data[i][j]);
                delay(10);
            }
        }
    }
    return;
}

void sendData(double data){
    Serial.print((data));
}

This is readSerial function:

void serial::readSerial(){
    serialData = arduino.readAll();
    qDebug()<< serialData <<"\n"; 
}

QML file:

import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    visible: true
    width: 17*square_size
    height: 17*square_size
    title: qsTr("Hello World")
    property int  square_size: 30
    Grid {
        id: grid
        columns: 17
        Repeater{
            id: rpt
            model: 17*17
            Rectangle{
                width: square_size
                height: square_size
                border.color: "black"
                border.width: 1

                Text {
                    anchors.centerIn: parent
                    text: Serial.model_data[index]
                }
            }
        }
    }
}

serial.h:

#include <QQmlApplicationEngine>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QtDebug>
class serial: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<QString> text READ text  NOTIFY textChanged)

public:
    explicit serial(QQmlApplicationEngine *engine, QObject *parent = nullptr);
    ~serial();
    void setupSerial();

    Q_INVOKABLE QList<QString> text(){
        return m_text;
    }

private slots:
    void readSerial();
private:
    QQmlApplicationEngine* m_engine;

/* Varian of Arduino*/
    QSerialPort arduino;
    bool arduino_is_avaiable;
    QString portName;
    QByteArray serialData;

/*Varian of text*/
    QList<QString> m_text;
signals:
    void textChanged();

public slots:

};

#endif // SERIAL_H

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "serial.h"

int main(int argc, char *argv[]) 
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    serial myserial(&engine);
    engine.rootContext()->setContextProperty("Serial", &myserial);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

Solution

  • I think you are missing the property on the Serial class to read the data: text: Serial.model_data[index]. The fastest solution to get something on screen would be to add that property and fill it as follows:

    Serial.h (I left some parts out)

    class Serial : public QObject
    {
        Q_OBJECT
    
        Q_PROPERTY(QVariantList model_data READ model_data NOTIFY modelDataChanged)
    
    public:
        explicit Serial(QObject *parent = nullptr);
    
        QVariantList model_data() const { return model_data_; }
    
    signals:
        void modelDataChanged();
    
    private slots:
        void readSerial();
    
    private:
        QVariantList model_data_;
    };
    

    The readSerial() function would look like this:

    void Serial::readSerial()
    {
        QByteArray serialData = QByteArray(17 * 17 * 8, 0); //shortcut for testing
    
        double *arr = reinterpret_cast<double*>(serialData.data());
        model_data_.clear();
        for(int i=0;i<17*17;i++)
        {
            model_data_.append(arr[i]);
        }
        emit modelDataChanged();
    }
    

    What happens is that the QVariant list is filled with the doubles, which have been reinterpreted from byte to doubles. Note that this has to be done every time the serialData changes.

    However, this might not be ideal in case you want to go any further with this. When changing dimensions, this setup will fail, both on arduino sending side, arduino reading side and on qml side. You should consider sending the dimensions of the array, reading those back and acting on it. One idea might be QAbstractListModel, which already has the notion of rows/columns; another, simpler idea might be to add properties to the Serial class stating the dimensions (which where read in readSerial())