首页 > 解决方案 > 如何使用Repeater和GridView将二维数组的值从C++显示到QML

问题描述

从 C++ 在 QML 上显示二维数组 QString 的值时出现问题

我有要在 QML 上使用的数据和 qmlRegisterType。

这是 QML 文件:

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]
                    }
                }
            }
        }
    }
}

这是 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();
 }

串行.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

串行.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

我收到了数据,但无论何时更改数据,我都无法在 QML 上显示它。我将其设置为更改 1view/sec。我的逻辑是:每当数据发生变化时,QML 都会显示新数据

标签: c++qtgridviewqmlsignals-slots

解决方案


在您的代码中,我看到以下错误:

  • 或者您使用 qmlRegisterType 注册类型或将其设置为 contextProperty,而不是两者。我建议您检查选择 C++ 和 QML 之间的正确集成方法

  • 在您的转发器中,您正在创建 N MySerial 但您只能拥有 1 个,想法是您创建一个 MySerial 并将信息传递给模型。

  • 不要使用QList<QString>但是QStringList

  • 您的数据不应从 QML 写入,因此 modelData 属性不必为 Writeble。

考虑到上述情况并避免部分数据解码,因为我不知道将取代它的格式创建随机数据,解决方案如下:

串行.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

串行.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();
}

主文件

#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
                }
            }
        }
    }
}

推荐阅读