传递到QML的QList<QList<QString>>

6
我正在尝试将一个二维 QList 作为 Q_PROPERTY 传递到 QML 中,但是在 QML 中我无法实际访问任何信息。
一些代码:
C++: Q_PROPERTY 在构造函数中由 q_invokable 函数填充:
void Class::createNewGameArray(){
QList<QList<QString>> testArray;

for( int i = 0; i < _intervals.size(); ++i) {
    QList<QString> innerArray;
    testArray.append(innerArray);
        testArray[i].append(_intervals[i]);
        testArray[i].append("Audio");
}
for( int i = 0; i < _intervals.size(); ++i) {
    QList<QString> innerArray;
    testArray.append(innerArray);
        testArray[i+12].append(_intervals[i]);
        testArray[i+12].append("Text");
}
 std::random_shuffle(testArray.begin(),testArray.end());
Class::setGameArray(testArray);
emit gameArrayChanged(_newGameArray);

这返回了这个:
(("M7", "Text"), ("M3", "Text"), ("m3", "Text"), ("M6", "Audio"), ("TT", "Audio"), ("P4", "Text"), ("m7", "Audio"), ("m2", "Text"), ("m6", "Audio"), ("m6", "Text"), ("M7", "Audio"), ("P5", "Text"), ("P4", "Audio"), ("m2", "Audio"), ("M2", "Audio"), ("M3", "Audio"), ("P5", "Audio"), ("m3", "Audio"), ("M6", "Text"), ("TT", "Text"), ("m7", "Text"), ("Oct", "Audio"), ("Oct", "Text"), ("M2", "Text"))

我想要的正是这个。

在 main.cpp 中,我设置了 rootContext 如下:

Class object;

QQmlApplicationEngine engine;
QQmlContext* context = engine.rootContext();

context->setContextProperty("object", &object);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

然而,在 QML 中,我只得到了以下内容:
qml: QVariant(QList>)
我无法对其进行任何操作。
我的目标是能够以以下方式从 QML 访问 2D QList:
object.gameArray[0][1] // 返回 "Text"
我可以在普通 QList(没有 2D)中做到这一点。非常感谢您的帮助!

最干净的方法可能是将列表封装在 QAbstractItemModel (QAbstractTableModel) 中。最简单的方法是使用 QQmlListProperty - m7913d
我会查一下,谢谢! - Leshii
2个回答

9

QML本身不支持理解QList,因此通常情况下无法传递任何类型T的QList并使QML能够访问列表中的项目。

然而,QML引擎确实内置了对一些特定类型的QList的支持:

  • QList<QObject *>
  • QList<QVariant>
  • QStringList - (不是QList<QString>!!!)

因此,如果您可以使用上述3种类型的任意组合构建您的列表,则可以拥有一个工作解决方案。在您的用例中,我建议使用以下结构:

QList<QVariant(QStringList)>

在我们尝试之前,一个最终的注意事项...仅仅因为这样可以工作,并不一定意味着这是一个好主意。 QList内容会在运行时复制到Javascript数组中,因此从C++对任何列表进行微小更新都将导致整个列表重新构造为新的Javascript数组,这可能是昂贵的。

现在,让我们来试试吧...

myclass.h

#ifndef MYCLASS_H
#define MYCLASS_H
#include <QStringList>
#include <QVariant>

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<QVariant> variantList READ variantList NOTIFY variantListChanged)

public:
    explicit MyClass(QObject *parent = nullptr) : QObject(parent),
        m_variantList({
                      QStringList({ "apple", "banana", "coconut" }),
                      QStringList({ "alice", "bob", "charlie" }),
                      QStringList({ "alpha", "beta", "gamma" })
        }) { }

    QList<QVariant> variantList() const { return m_variantList; }

signals:
    void variantListChanged();

public slots:

private:
    QList<QVariant> m_variantList;
};

#endif // MYCLASS_H

main.qml

import QtQuick 2.7
import QtQuick.Controls 2.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480

    Column {
        id: column

        // will add the strings here from the handler below
    }

    Component.onCompleted: {
        console.log("variantList length %1".arg(myClass.variantList.length))

        for (var i = 0; i < myClass.variantList.length; i++) {

            console.log("stringList %1 length %2".arg(i).arg(myClass.variantList[i].length))

            for (var j = 0; j < myClass.variantList[i].length; j++) {
                // print strings to the console
                console.log("variantList i(%1), j(%2) = %3".arg(i).arg(j).arg(myClass.variantList[i][j]))

                // add the strings to a visual list so we can see them in the user interface
                Qt.createQmlObject('import QtQuick 2.7; Text { text: "i(%1), j(%2) = %3" }'.arg(i).arg(j).arg(myClass.variantList[i][j]), column)
            }
        }
    }
}

main.cpp

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

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

    QQmlApplicationEngine engine;

    MyClass myClass;
    engine.rootContext()->setContextProperty("myClass", &myClass);

    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

运行时输出

qml: variantList length 3
qml: stringList 0 length 3
qml: variantList i(0), j(0) = apple
qml: variantList i(0), j(1) = banana
qml: variantList i(0), j(2) = coconut
qml: stringList 1 length 3
qml: variantList i(1), j(0) = alice
qml: variantList i(1), j(1) = bob
qml: variantList i(1), j(2) = charlie
qml: stringList 2 length 3
qml: variantList i(2), j(0) = alpha
qml: variantList i(2), j(1) = beta
qml: variantList i(2), j(2) = gamma

可视化输出

......它有效 :)


0

自动转换只适用于几种特定类型的容器,仅此而已。仅因为转换A和转换B有效,并不意味着转换A也会有效。

在所有自动转换无法使用的情况下,您几乎可以忘记使用[]运算符。

然而,变体列表的变体列表可能会奏效。我自己没有测试过,但有一线希望。但是,在将该内容传递给QML之前,您必须手动进行转换。

最肯定有效的方法是创建访问器函数,例如QString Class::get(int row, int col),或者您可以拥有单独的访问器来选择一行,然后将该结果传递给另一个函数以选择列并提供字符串。


感谢您的分解,我喜欢访问器函数的想法。谢谢! - Leshii
你也可以使用模型,但除非你在处理QML方面的视图,否则这并不是必需的。 - dtech

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接