TrungPC
TrungPC

Reputation: 57

How to display value of 2D Array to QML from C++, using Repeater and GridView

I have problem when display value of 2D array QString on QML from C++

I have data and a qmlRegisterType to use on QML.

This is QML file:

import QtQuick 2.12
import QtQuick.Window 2.2
import io.myserial 1.0
import QtQuick.Controls 2.3
Window {
    visible: true
    width: 8*square_size
    height: 8*square_size
    title: qsTr("Matrix LDR Value")
    property int  square_size: 50
    Grid {
        id: grid
        columns: 8
        Repeater{
            id: rpt
            model: 8*8
            Rectangle{
                width: square_size
                height: square_size
                border.color: "black"
                border.width: 1

                Text {
                    id: txt
                    anchors.centerIn: parent
                }
                MSerial{
                    onModelDataChanged:{
                        txt.text = Serial.model_data[i]
                    }
                }
            }
        }
    }
}

This is main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "serial.h"
int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);  

    qmlRegisterType<Serial>("io.myserial", 1, 0, "MSerial");

    QQmlApplicationEngine engine;

    Serial mySerial(&engine);
    engine.rootContext()->setContextProperty("Serial", &mySerial);

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
 }

serial.h

#ifndef SERIAL_H
#define SERIAL_H
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QQmlApplicationEngine>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QtDebug>
#include <QObject>
#include <QString>
#include <QString>
#include "toInt16.h"

class Serial: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<QString> modelData READ modelData WRITE setModelData NOTIFY modelDataChanged)

public:

    explicit Serial(QObject *parent = nullptr);

    QList<QString> modelData();

    Q_INVOKABLE void setModelData(const QList<QString> &modelData);
    void ReadSerial();

    void setUpSerial();
    QByteArray serialData;
    QSerialPort stm32;
    QString portName;
    QString buffer;
    bool isStm32Avaiable;
private slots:
    void readSerial();
signals:
    void modelDataChanged();

private:
    QList<QString> myModelData;

public slots:

};

#endif // SERIAL_H

serial.cpp

#include "serial.h"
#include "toInt16.h"



Serial::Serial(QObject *parent) : QObject(parent)
{
    setUpSerial();
}

QList<QString> Serial::modelData()
{
    return myModelData;
}


void Serial::setUpSerial(){
    buffer = "";
    isStm32Avaiable = false;
    portName = "";
    qDebug()<<"Num port: "<<QSerialPortInfo::availablePorts().length();

    foreach (const QSerialPortInfo &serialPortInfor,QSerialPortInfo::availablePorts()) {
        qDebug()<<"Has Vendo ID: "<<serialPortInfor.hasVendorIdentifier();
        if(serialPortInfor.hasVendorIdentifier()){
            qDebug()<<"Vendo ID: "<<serialPortInfor.vendorIdentifier();
        }
        qDebug()<<"Has Product ID: "<<serialPortInfor.hasProductIdentifier();
        if(serialPortInfor.hasProductIdentifier()){
            qDebug()<<"Product ID: "<<serialPortInfor.productIdentifier();
            portName = serialPortInfor.portName();
        }
        if(QSerialPortInfo::availablePorts().length() >0){
            isStm32Avaiable = true;
        }
    }
    if(isStm32Avaiable){
        stm32.setPortName(portName);
        stm32.open(QSerialPort::ReadWrite);
        stm32.setBaudRate(QSerialPort::Baud115200);
        stm32.setDataBits(QSerialPort::Data8);
        stm32.setParity(QSerialPort::NoParity);
        stm32.setStopBits(QSerialPort::OneStop);
        stm32.setFlowControl(QSerialPort::NoFlowControl);
        QObject::connect(&stm32, SIGNAL(readyRead()),this,SLOT(readSerial()));


    }else{

        qDebug()<<"warning: Port Error . Couldn't find kit";
    }
}

void Serial::setModelData(const QList<QString> &modelData)
{
    if (modelData == myModelData)
        return;

    myModelData = modelData;
    emit modelDataChanged();
}


void Serial::ReadSerial()
{
    serialData.clear();
    serialData = stm32.readAll();
    QByteArray buffer;
    qDebug()<< "Serial Data: "<<serialData;
    buffer = serialData;//.split(',');
    // QStringList buffer2;

    //uint16_t data[64];
    union INT_TO_BYTE receivedData[64];

    for(int i=0; i<64; i++){
        receivedData[i].b[0] = buffer.data()[i*2];
        receivedData[i].b[1] = buffer.data()[i*2+1];
        receivedData[i].i = (uint16_t)receivedData[i].b[0]|(uint16_t)receivedData[i].b[1]<<8;
        qDebug() << "This is data "<<i<<" "<<receivedData[i].i;
        myModelData.append(QString::number(receivedData[i].i));
    }
    //setModelData(myModelData);
    emit modelDataChanged();
}

toInt16.h

#ifndef TOINT16_H
#define TOINT16_H

#include <QTextCodec>

union INT_TO_BYTE
{
    uint16_t i;
    char b[2];
};
//union INT_TO_BYTE receivedData[128];



#endif // TOINT16_H

I received data but I cannot display it on QML whenever data is changed. I set it change 1view/sec. My logic is: Whenever data change, QML display new data

Upvotes: 1

Views: 680

Answers (1)

eyllanesc
eyllanesc

Reputation: 244132

In your code I see the following errors:

  • Or you register a type with qmlRegisterType or set it as contextProperty, not both. I recommend you check Choosing the Correct Integration Method Between C++ and QML.

  • In your repeater you are creating N MySerial but you can only have 1, the idea is that you create a MySerial and the information is passed to the model.

  • Do not use QList<QString> but QStringList.

  • Your data should not be written from QML so it is not necessary for the modelData property to be Writeble.

Considering the above and avoiding the part of the decoding of the data since I do not know the format that will replace it creating random data the solution is the following:

serial.cpp

#ifndef SERIAL_H
#define SERIAL_H

#include <QObject>
#include <QSerialPort>

class Serial : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QStringList modelData READ modelData NOTIFY modelDataChanged)
public:
    explicit Serial(QObject *parent = nullptr);
    QStringList modelData() const;
Q_SIGNALS:
    void modelDataChanged();
private Q_SLOTS:
    void readSerial();
private:
    void setUpSerial();
    QStringList m_modelData;
    bool isStm32Avaiable;
    QString portName;
    QSerialPort stm32;
};

#endif // SERIAL_H

serial.cpp

#include "serial.h"
#include "toInt16.h"

#include <QSerialPortInfo>
#include <QDebug>

Serial::Serial(QObject *parent) : QObject(parent){
    m_modelData.reserve(64);
    setUpSerial();
}

QStringList Serial::modelData() const{
    return m_modelData;
}

void Serial::setUpSerial(){
    isStm32Avaiable = false;
    portName = "";
    qDebug()<<"Num port: "<<QSerialPortInfo::availablePorts().length();
    for (const QSerialPortInfo &serialPortInfor : QSerialPortInfo::availablePorts()) {
        qDebug()<<"Has Vendo ID: "<<serialPortInfor.hasVendorIdentifier();
        if(serialPortInfor.hasVendorIdentifier()){
            qDebug()<<"Vendo ID: "<<serialPortInfor.vendorIdentifier();
        }
        if(serialPortInfor.hasProductIdentifier()){
            qDebug()<<"Product ID: "<<serialPortInfor.productIdentifier();
            portName = serialPortInfor.portName();
        }
        if(!QSerialPortInfo::availablePorts().isEmpty()){
            isStm32Avaiable = true;
            break;
        }
    }
    if(isStm32Avaiable){
        stm32.setPortName(portName);
        stm32.open(QSerialPort::ReadWrite);
        stm32.setBaudRate(QSerialPort::Baud115200);
        stm32.setDataBits(QSerialPort::Data8);
        stm32.setParity(QSerialPort::NoParity);
        stm32.setStopBits(QSerialPort::OneStop);
        stm32.setFlowControl(QSerialPort::NoFlowControl);
        connect(&stm32, &QIODevice::readyRead, this, &Serial::readSerial);
    }else{
        qDebug()<<"warning: Port Error . Couldn't find kit";
    }
}

void Serial::readSerial(){
    m_modelData.clear();
    // FIXME
    static int counter;
    for(int i=0; i<64; i++){
        m_modelData.append(QString::number(counter));
        counter++;
    }
    //
    emit modelDataChanged();
}

main.cpp

#include "serial.h"

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    qmlRegisterType<Serial>("io.myserial", 1, 0, "MSerial");
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

main.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import io.myserial 1.0

Window {
    visible: true
    width: 8*square_size
    height: 8*square_size
    title: qsTr("Matrix LDR Value")
    property int  square_size: 50
    MSerial{
        id: serial
    }
    Grid {
        columns: 8
        Repeater{
            model: serial.modelData
            Rectangle{
                width: square_size
                height: square_size
                border.color: "black"
                border.width: 1
                Text {
                    id: txt
                    anchors.centerIn: parent
                    text: model.modelData
                }
            }
        }
    }
}

Upvotes: 2

Related Questions