Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I'm trying to pass a 2d QList as a Q_PROPERTY into QML, however, inside QML and i am unable to actually access any of the information.
some code:
the q_property get populated by a q_invokable function in the constructor:
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);
which returns this:
(("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"))
exactly what i want.
i set the rootContext like so in main.cpp:
Class object;
QQmlApplicationEngine engine;
QQmlContext* context = engine.rootContext();
context->setContextProperty("object", &object);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
however, inside qml i only get
qml: QVariant(QList<QList<QString> >)
and am unable to actually do anything with it.
My goal, ideally, would be to be able to access the 2d qlist from qml in this manner:
object.gameArray[0][1]
// return "Text"
I'm able to do this with regular QLists (without the 2d). Any help would be greatly appreciated!
–
QML does not inherently understand QLists, so in general it is not possible to pass in a QList of any type T and have QML able to access the items inside the list.
However, the QML engine does have built in support for a few specific types of QList:
QList<QObject *>
QList<QVariant>
QStringList
- (not QList<QString>
!!!)
Therefore if you can construct your list of lists using any combination of the 3 types above, then you can have a working solution. In your use case I would suggest the following construction:
QList<QVariant(QStringList)>
A final note before we try it... Just because this will work, it does not necessarily mean that it is a good idea. The QList contents are copied to Javascript arrays at runtime, and therefore any minor updates to any of the lists from the C++ will cause the entire list to be reconstructed as a new Javascript array, which could be expensive.
Now, let's try it...
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();
Runtime output
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
Automatic conversions would only work for several specific types of containers, and that's it. Just because conversion A works, and conversion B works, doesn't mean that conversion A will work too.
You can pretty much forget about using the []
operator in all the cases where automatic conversion doesn't work.
A variant list of variant lists however might just work. I haven't tested it myself but there is a slim hope. However, you will have to manually do the conversion before you pass that stuff to QML.
An approach that will most definitely work is to create accessor functions, like for example QString Class::get(int row, int col)
or you can have separate accessors to select a row, and then pass that result to another function to select a column to give you the string.
–
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.