Si j'ai une liste de choses en C++, comment puis-je l'exposer à QML (dans Qt5/QtQuick 2)? Il semble que QML ne peut comprendre que les classes dérivées de QObject
, ce qui pose problème, car QObject
s ne peut pas être placé dans une QList
ou copié. Comment puis-je faire cela:
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;
// ...
};
Pour que je puisse faire quelque chose comme ça dans QML :?
var a = thingManager.things[0].name;
Après plus d'expérience avec QML, j'ai trouvé le meilleur moyen d'avoir des listes de choses avec QAbstractListModel
.
Vous faites que votre Thing
dérive de QObject
pour pouvoir être stocké dans un QVariant
(après l’avoir enregistré). Vous pouvez ensuite renvoyer la valeur réelle Thing
en tant qu’élément du modèle. Vous pouvez y accéder dans Repeater
en tant que model.display.a_property_of_thing
. La longueur de la liste est disponible sous la forme model.count
.
Cela a les avantages et les inconvénients suivants:
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];
}
Je suis tombé sur cette question en essayant de résoudre un problème similaire, où je voulais utiliser du code C++ en tant que source de modèle dans QML. La réponse donnée par TheBootroo m'a orienté dans la bonne direction, mais n'a pas fonctionné pleinement pour moi. Je n'ai pas assez de réputation pour lui répondre directement (mais j'ai relu sa réponse).
J'utilise Qt 5.0.0 J'ai trouvé ce lien très utile
La définition de ThingManager doit être modifiée comme suit
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;
};
Notez que j'ai changé le type de retour de getThings en QList <QObject *>. Sans cette modification, Qt avertit qu'il est "Impossible de gérer le type de données non enregistré 'QList <Thing *>'".
Dans le code QML, les propriétés de Thing sont accessibles via le modèle en tant que model.modelData.size et model.modelData.name.
Sinon, vous pouvez utiliser QVariantList
(QList<QVariant>
), il passera automatiquement au tableau JavaScript lorsqu'il est passé à QML, et il est lu et écrit en C++ et QML
Ah j'ai trouvé la réponse (je pense, pas testé): QQmlListProperty
Il y a quelques utilisations dans les exemples, par exemple: à qtdeclarative/examples/quick/tutorials/gettingStartedQml/filedialog/directory.*
:
Malheureusement, vous ne pouvez avoir que des listes en lecture seule pour le moment.
vous avez tout à fait tort à propos de QObject, ils peuvent être donnés à une QList, simplement sous la forme d'un pointeur, car ce qui suit fonctionne parfaitement:
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;
};
meilleure façon d'utiliser QQmlListProperty . voir cet exemple simple, j'espère vous aider ...
Exemple de types de propriétés d'objet et de liste
La réponse donnée par eatyourgreens
est correcte. En implémentant votre classe de cette manière, vous pouvez accéder à autant de descendants que vous le souhaitez. Un autre conseil utile que j'ai trouvé utile consiste à créer un alias pour notre modèle dans l'élément délégué qml.
ListView {
anchors.fill: parent
model: thing_manager.things
delegate: ItemDelagate {}
clip: true
spacing: 10
}
Et ensuite, dans ItemDelegate.qml, vous pouvez créer un alias pour le modèle afin de ne pas utiliser tout le temps le modèle.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
}
}
}
Une façon très indirecte d'y parvenir est la suivante:
i.) Faire un modèle en qml
ListModel
{
id: thingModel
ListElement
{
size: 10
name: "Apple"
}
}
ii.) Ensuite, fournissez quelques fonctions javascript pour modifier cette liste, par exemple.
function jAppendThing( newSize, newName )
{
thingModel.append({"size": nameSize, "name": newName })
}
function jClearThing()
{
thingModel.clear()
}
de même jDeleteThing etc ..
iii.) Vous pouvez lire sur comment appeler des fonctions qml depuis c ++
iv.) Exécutez une boucle sur votre liste C++ et appelez la fonction append de qml pour ajouter également toutes ces données à la liste qml.
v.) Sur toute mise à jour dans la liste latérale C++, modifiez également les données qml en utilisant la fonction ci-dessus pour les maintenir à jour.
Existe une bonne solution, mais ne mentionne pas la solution:
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;
// ...
};
Lire et écrire sont applicables. Pas d'appel de fonction coûteux ni de copie de données. Juste un accès direct aux membres de la classe dans QML:
var a = thingManager.things[0].name;
Pour plus d'informations, voir la doc: https://doc-snapshots.qt.io/qt5-dev/properties.html