Accediendo a C++ QLists desde QML
qt5 qtquick2 (9)
Ah encontré la respuesta (creo, no probada): QQmlListProperty
Hay algunos usos en los ejemplos, por ejemplo, en qtdeclarative/examples/quick/tutorials/gettingStartedQml/filedialog/directory.*
:
Desafortunadamente, solo puedes tener listas de solo lectura en este momento.
Si tengo una lista de cosas en C ++, ¿cómo expongo eso a QML (en Qt5 / QtQuick 2)? Parece que QML solo puede entender las clases derivadas de QObject
, lo cual es un problema porque los QObject
s no se pueden poner en una QList
o copiar. Cómo hago esto:
struct Thing
{
int size;
QString name;
};
class ThingManager : public QObject
{
Q_OBJECT
// These macros support QtQuick, in case we one day want to use it to make a slick
// interface (when QML desktop components are released).
Q_PROPERTY(QList<Thing> things READ things NOTIFY thingssChanged)
public:
// ...
QList<Thing> things() const;
// ...
};
¿Para que pueda hacer algo como esto en QML?
var a = thingManager.things[0].name;
Alternativamente, puede usar QVariantList
( QList<QVariant>
), cambiará automáticamente a la matriz de JavaScript cuando se pase a QML, y es de lectura y escritura desde C ++ y QML.
Después de más experiencia con QML, he encontrado que la mejor manera de tener listas de cosas es con un QAbstractListModel
.
Usted hace que su Thing
derive de QObject
para que pueda almacenarse en un QVariant
(después de registrarlo). Luego puedes devolver la Thing
real como el elemento del modelo. Puede acceder a él en un Repeater
como model.display.a_property_of_thing
. La longitud de la lista está disponible como model.count
.
Esto tiene los siguientes pros y contras:
- Rápido: no copia la lista completa para acceder a un elemento.
- Puede obtener fácilmente animaciones para los cambios en la lista (adición, reorganización y eliminación de elementos).
- Es fácil de usar desde QML.
- Para habilitar las animaciones para que funcionen, siempre que cambie la lista, debe realizar una contabilidad ligeramente incómoda (
beginInsertRows()
etc.)
...
class Things : public QObject
{
...
};
Q_DECLARE_METATYPE(Thing*)
class ThingList : public QAbstractListModel
{
Q_OBJECT
public:
explicit ThingList(QObject *parent = 0);
~ThingList();
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
public slots:
// Extra function to get the thing easily from outside Repeaters.
Thing* thing(int idx);
private:
QList<Thing*> mThings;
};
int ThingList::rowCount(const QModelIndex& parent) const
{
return mThings.size();
}
QVariant ThingList::data(const QModelIndex& index, int role) const
{
int i = index.row();
if (i < 0 || i >= mPorts.size())
return QVariant(QVariant::Invalid);
return QVariant::fromValue(mThings[i]);
}
Thing* ThingList::thing(int idx)
{
if (idx < 0 || idx >= mThings.size())
return nullptr;
return mThings[idx];
}
Existe una buena solución, pero no se menciona:
class ThingManager : public QObject
{
Q_OBJECT
// These macros support QtQuick, in case we one day want to use it to make a slick
// interface (when QML desktop components are released).
Q_PROPERTY(QList<Thing> things MEMBER m_things NOTIFY thingssChanged)
// ...
private:
// ...
QList<Thing> m_things;
// ...
};
Leer y escribir son aplicables. Sin función de llamada costosa y copia de datos. Solo acceso directo a los miembros de la clase en QML:
var a = thingManager.things[0].name;
Para obtener más información, consulte el doc: https://doc-snapshots.qt.io/qt5-dev/properties.html
La mejor manera de usar QQmlListProperty esta muestra simple, espero que le ayude.
Ejemplo de tipos de propiedades de objetos y listas
La respuesta dada por eatyourgreens
es correcta. Al implementar su clase de esa manera, puede acceder a tantos descendientes como desee. Un consejo más útil que encontré útil es crear un alias para nuestro modelo dentro del elemento delegado qml.
ListView {
anchors.fill: parent
model: thing_manager.things
delegate: ItemDelagate {}
clip: true
spacing: 10
}
Y luego, en el ItemDelegate.qml puede crear un alias para que el modelo no use todo el tiempo que model.modelData
Item{
width: 600
height: 200
property var thing: model.modelData
Rectangle {
anchors.fill: parent
color: "red"
Text {
text: thing.name // or any other field
}
}
}
Me encontré con esta pregunta al intentar solucionar un problema similar, en el que quería usar el código C ++ como fuente modelo en QML. La respuesta dada por TheBootroo me indicó la dirección correcta, pero no funcionó completamente para mí. No tengo la reputación suficiente para responderle directamente (pero sí voté su respuesta).
Estoy usando Qt 5.0.0. Encontré este enlace muy útil.
La definición de ThingManager se debe cambiar de la siguiente manera
class ThingManager : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<QObject*> things READ getThings NOTIFY thingsChanged)
public:
QList<QObject*> getThings () const { return m_things; }
signals:
void thingsChanged ();
private:
QList<QObject*> m_things;
};
Tenga en cuenta que cambié el tipo de retorno de getThings a una QList <QObject *>. Sin este cambio, Qt advierte que es "No se puede manejar el tipo de datos no registrado ''QList <Thing *>''".
En el código QML, se puede acceder a las propiedades de Thing a través del modelo como model.modelData.size y model.modelData.name.
Una forma altamente indirecta de lograrlo es esta:
i.) Hacer un modelo en qml
ListModel
{
id: thingModel
ListElement
{
size: 10
name: "Apple"
}
}
ii.) Luego proporcione un par de funciones javascript para modificar esta lista, por ejemplo.
function jAppendThing( newSize, newName )
{
thingModel.append({"size": nameSize, "name": newName })
}
function jClearThing()
{
thingModel.clear()
}
de manera similar jDeleteThing etc.
iii.) Puede leer sobre cómo llamar a las funciones qml desde c ++
iv.) Ejecute un bucle en su lista de C ++ y llame a la función de adición de qml para agregar todos esos datos a la lista de qml también.
v.) En cualquier actualización en la lista lateral de C ++, modifique los datos qml y utilice la función anterior para mantenerlos actualizados.
Usted está bastante equivocado con respecto a QObject, se pueden entregar a una QList, simplemente en la forma de un puntero, como sigue perfectamente:
class Thing : public QObject
{
Q_OBJECT
Q_PROPERTY (int size READ getSize CONSTANT)
Q_PROPERTY (QString name READ getName CONSTANT)
public:
Thing(QObject * parent = NULL) : QObject(parent) {}
int getSize () const { return m_size; }
QString getName () const { return m_name; }
private:
int m_size;
QString m_name;
};
class ThingManager : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<Thing*> things READ getThings NOTIFY thingsChanged)
public:
QList<Thing*> getThings () const { return m_things; }
signals:
void thingsChanged ();
private:
QList<Things*> m_things;
};