Accès aux listes C++ QL à partir de QML
si j'ai une liste de choses en C++, Comment puis-je l'exposer à QML (en Qt5 / QtQuick 2)? Il semble que QML ne peut comprendre que QObject
- classes dérivées, ce qui est un problème parce que QObject
s ne peut pas être mis dans un QList
ou copié. Comment dois-je faire ceci:
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;
9 réponses
je suis tombé sur cette question en essayant de corriger un problème similaire, où je voulais utiliser du code C++ comme source modèle dans QML. La réponse donnée par TheBootroo m'a indiqué 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 pris bonne note de sa réponse).
j'utilise Qt 5.0.0 J'ai trouvé ce lien très utile
La définition de ThingManager devrait être changée comme suit: 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;
};
a Noter que j'ai changé le type de retour de getThings à une QList
dans le code QML, les propriétés de Thing sont accessibles via le model as model.modelData.taille et modèle.modelData.nom.
Alternativement, Vous pouvez utiliser QVariantList
(QList<QVariant>
), il se transforme automatiquement en tableau JavaScript lorsqu'il est passé à QML, et il est capable de lire et d'écrire à partir de C++ et QML
après plus d'expérience avec QML j'ai trouvé la meilleure façon d'avoir des listes de choses est avec un QAbstractListModel
.
Vous faites votre Thing
tirer QObject
donc il peut être stocké dans un QVariant
(après inscription). Ensuite, vous pouvez retourner le réel Thing
comme l'élément de modèle. Vous pouvez y accéder dans un Repeater
model.display.a_property_of_thing
. La longueur de la liste est disponible en model.count
.
C'est la suivante des avantages et des inconvénients:
- Fast - il n'a pas copiez la liste entière pour accéder à un élément.
- vous pouvez facilement obtenir des animations pour des changements à la liste (Ajout, réarrangement et suppression d'éléments).
- il est facile à utiliser à partir de QML.
- pour permettre aux animations de fonctionner, chaque fois que vous changez la liste, vous devez faire un peu de comptabilité faffy (
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];
}
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 sur QObject, ils peuvent être donnés à une QList, simplement sous la forme d'un pointeur, comme 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;
};
La réponse donnée par eatyourgreens
est correct. En mettant en œuvre votre classe de cette façon, vous pouvez accéder à autant de descendants que vous le souhaitez. Un autre conseil utile que j'ai trouvé utile est de créer un alias pour notre modèle à l'intérieur de l'élément délégué qml.
ListView {
anchors.fill: parent
model: thing_manager.things
delegate: ItemDelagate {}
clip: true
spacing: 10
}
et puis dans la rubrique Delegate.qml vous pouvez créer un alias pour que le model n'utilise pas tout le temps le 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
}
}
}
utilisation de la meilleure façon QQmlListProperty
.voir cet exemple simple , je l'espère, vous aider.
Type D'objet et type de propriété exemple
j'.) Faire un modèle en qml
ListModel
{
id: thingModel
ListElement
{
size: 10
name: "Apple"
}
}
ii.) Puis fournir quelques fonctions javascript pour modifier cette liste par exemple.
function jAppendThing( newSize, newName )
{
thingModel.append({"size": nameSize, "name": newName })
}
function jClearThing()
{
thingModel.clear()
}
iii.) Vous pouvez lire à ce sujet comment appeler les fonctions qml à partir de c++
iv.) Lancez une boucle sur votre liste C++ et appelez la fonction d'ajout de qml pour ajouter toutes ces données dans la liste qml comme bien.
v.) sur toute mise à jour de la liste côté C++, modifiez les données qml en utilisant la fonction ci-dessus pour les garder à jour.
Existe bien, mais n'a pas mentionné 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 de fonction coûteuse appel et copie de données. Accès direct aux membres de la classe dans QML:
var a = thingManager.things[0].name;
https://doc-snapshots.qt.io/qt5-dev/properties.html