QList<QList <QString >> передается в QML

Я пытаюсь передать 2d 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"))

именно то, что я хочу.

я установил rootContext так в main.cpp:

Class object;

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

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

однако внутри qml я получаю только

qml: QVariant(QList<QList<QString> >)

и я не могу ничего с этим поделать.

В идеале моя цель - получить доступ к 2d qlist из qml следующим образом:

object.gameArray [0] [1] // возвращаем "Текст"

Я могу сделать это с обычными QLists (без 2d). Любая помощь будет принята с благодарностью!

2 ответа

QML по своей сути не понимает QLists, поэтому в общем случае невозможно передать QList любого типа T и иметь 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

визуальный вывод

... и это работает:)

Автоматические преобразования будут работать только для нескольких конкретных типов контейнеров, и все. То, что преобразование A работает, а преобразование B работает, не означает, что преобразование A тоже будет работать.

Вы можете забыть об использовании [] оператор во всех случаях, когда автоматическое преобразование не работает.

Однако список вариантов списков вариантов может просто работать. Я не проверял это сам, но есть небольшая надежда. Однако вам придется вручную выполнить преобразование, прежде чем передать этот материал в QML.

Подход, который наиболее определенно будет работать, заключается в создании функций доступа, как, например, QString Class::get(int row, int col) или вы можете иметь отдельные средства доступа для выбора строки, а затем передать этот результат другой функции, чтобы выбрать столбец, чтобы дать вам строку.

Другие вопросы по тегам