从Cpp到QML在结构内部写入数组

时间:2018-12-14 16:59:16

标签: c++ arrays qt qml

我需要从Cpp到QML编写一个数组(从外部C代码)。如前所述,这可能是一个XY问题,现在我首先描述我的基本意图。我使用的外部c程序按原样提供,并且我无法更改。该c程序提供以下结构和函数mx_get,以从特定位置获取数据:

typedef struct Tmatrix
{
    size_t rows;
    size_t cols;
    double *data;
} Tmatrix;

double mx_get(const Tmatrix *matrix, const size_t i, const size_t j)
{
    return *(matrix->data + i * matrix->cols + j);
}

我需要在我的QML应用程序中使用此C程序,即99%QML和1%Cpp。 cpp-part是将QML连接到c程序的类。我使用qmlRegisterType<MyTerminal>在QML中使用它。

MyTerminal.h:

#include <QObject>

extern "C"
{
    #include "external-c-program.h"
}
Q_DECLARE_METATYPE(Tmatrix)

class MyTerminal: public QObject
{
    Q_OBJECT

public:
    MyTerminal();
    Q_INVOKABLE void getAllPartitionQualities();
    /* and other stuff not relevant here... */

private:
    TPanel* Panel; /* this contains the Tmatrix at Panel->Q */
};

在QML部分,我想显示Tmatrix-> data的内容。因此,我目前在Text中使用Repeater

Repeater {
    model: nRows*nColumns
    Text {
        text: myTerminal.quality[indexY][indexX].toFixed(2)
        property int indexX: index - parseInt(index/nColumns)*nColumns
        property int indexY: parseInt(index/nRows)
    }
}

我逐个元素地完成了此操作,但是随着数组大小增加到19 * 19,现在大约需要20秒。 (在以下代码示例中,Panel->Q的类型为Tmatrix。)

MyTerminal.cpp:

for (int y=0; y<PARTITION_ROWS; y++)
{
    for (int x=0; x<PARTITION_COLUMNS; x++)
    {
        QMetaObject::invokeMethod(this, "setQuality",
                                  Q_ARG(QVariant, x),
                                  Q_ARG(QVariant, y),
                                  Q_ARG(QVariant, mx_get(Panel->Q, x, y)));
    }
}

QML:

MyTerminal {
    id: myTerminal
    property int nRows: 19
    property int nColumns: 19
    property var quality: [[]]

    Component.onCompleted: {
        // Initialize quality as 2d array with size nRows*nColumns
        var i, j;
        var temp = new Array(nRows);
        for (i=0; i<nRows; i++) {
            temp[i] = new Array(nColumns);
            for (j=0; j<nColumns; j++) {
                temp[i][j] = 0.0;
            }
        }
        quality = temp;
    }

    function setQuality(x, y, q) {
        quality[y][x] = q;
        // Assign to itself to trigger an update of the texts
        quality = quality;
    }
}

所以我现在正在尝试通过cpp中的一个调用来设置整个数组:

QQmlProperty::write(this, "quality", QVariant::fromValue(Panel->Q->data));

因此,我认为我需要添加以下内容:

Q_DECLARE_METATYPE(Tmatrix)

但是我仍然收到错误“静态断言失败:类型未注册,请使用Q_DECLARE_METATYPE宏使Qt的元对象系统知道它”。 可能是因为双指针位于结构内部?

将指针内容发送到QML的最佳方式(性能最高)是什么?

我还尝试使用QMetaObject :: invokeMethod传递Panel->Q(而不是将Panel->Q->data传递给QQmlProperty :: write),但是我也没有找到如何正确执行此操作的帮助。

编辑:还是可以在继承QObject并仍从QML访问它的Cpp类中声明数组quality?也许更容易。

1 个答案:

答案 0 :(得分:0)

  

将指针内容发送到QML的最佳方式(性能最高)是什么?

您不能直接发送指针本身。您需要将数据打包到QVariantListQVariantMap中。 (由于您使用的是双精度,因此也可以将其存储为QList<qreal>并将其传递给QML。)

可以通过

将您的TMatrix对象变成QList<QList<qreal>>
QList<QList<qreal>> tMatrix = {
    {0.0, 1.0, 2.0, 3.0},
    {4.0, 5.0, 6.0, 7.0},
    {8.0, 9.0, 10.0, 11.0}
};

这使将对象与C ++ / QML之间的相互抛出变得更容易。

更多信息:Data Type Conversion between QML and C++

  

还是可以在继承QObject并仍从QML访问它的Cpp类中声明数组质量?也许更容易。

是的,因为您的数据很大,所以可能更合适。但是请注意,您的数据 still 需要可转换为QML数据类型。 (再次,我建议为您的对象使用QVariantMap,因为这最终是JS处理对象的方式。)

这可能以C ++类的成员变量的形式出现,例如

private:
    QList<QList<qreal>> tMatrix = { /*...*/ };

然后可以使用数据值在构造函数中填充此矩阵。 (而且不一定是QList,也可以是double或另一个QList<>,但这取决于您的TMatrix的用途,因此由您决定。只需确保它是valid type。)

然后有一个公共插槽或可调用的方法,例如,可以从QML / JS中调用

public:
    Q_INVOKABLE qreal getObj(int x, int y);

像这样定义它

qreal MyClass::getObj(int x, int y)
{
    if (y <= 0 || reals.size() <= y)
        return qreal();

    if (x <= 0 || vMaps[y].size() <= x)
        return qreal();

    return tMatrix[y][x];
}

这只是吸气剂,如果您想要一个setter,则可以使用void返回类型和qreal自变量(允许您随后将JS对象传递到其中)来同样地定义它。 / p>

请记住expose your class to QML(我相信您已经这样做了),然后您可以使用...在QML / JS中访问tMatrix

MyClass  // depends on how you registered your type
{
    id: myClass
    Component.onCompleted
    {
        var obj = getObj(2, 1)  //  calls the function from your class
                                //  use an id if needed (e.g. myClass.getObj())

        console.debug("Retrieved Object at (2, 1):")
        console.debug(JSON.stringify(obj))            
    }
}

更多信息:Integrating QML and C++