Wenn ich eine Liste mit Dingen in C++ habe, wie kann ich diese in QML freigeben (in Qt5/QtQuick 2)? Es scheint, als könnte QML nur QObject
- abgeleitete Klassen verstehen, was ein Problem ist, da QObject
s nicht in eine QList
eingefügt oder kopiert werden kann. Wie mache ich das:
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;
// ...
};
Damit ich so etwas in QML machen kann :?
var a = thingManager.things[0].name;
Nach mehr Erfahrung mit QML habe ich herausgefunden, dass der beste Weg, Listen von Dingen zu haben, mit einem QAbstractListModel
ist.
Sie lassen Ihre Thing
von QObject
ableiten, damit sie in einem QVariant
(nach der Registrierung) gespeichert werden kann. Dann können Sie das aktuelle Thing
als Modellelement zurückgeben. Sie können in Repeater
als model.display.a_property_of_thing
darauf zugreifen. Die Listenlänge ist als model.count
verfügbar.
Dies hat folgende Vor- und Nachteile:
beginInsertRows()
usw.)....
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];
}
Ich bin auf diese Frage gestoßen, als ich versuchte, ein ähnliches Problem zu beheben, bei dem ich C++ - Code als Modellquelle in QML verwenden wollte. Die Antwort von TheBootroo wies mich in die richtige Richtung, funktionierte aber nicht für mich. Ich habe nicht genug Ruf, um ihm direkt zu antworten (aber ich habe seine Antwort bestätigt).
Ich verwende Qt 5.0.0 Ich fand diesen Link sehr hilfreich
Die Definition von ThingManager sollte wie folgt geändert werden
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;
};
Beachten Sie, dass ich den Rückgabetyp von getThings in eine QList <QObject *> geändert habe. Ohne diese Änderung warnt Qt, dass der nicht registrierte Datentyp 'QList <Thing *>' 'nicht verarbeitet werden kann.
Im QML-Code können die Eigenschaften von Thing als model.modelData.size und model.modelData.name über das Modell aufgerufen werden.
Alternativ können Sie QVariantList
(QList<QVariant>
) verwenden. Bei der Übergabe an QML wird das Feld automatisch in ein JavaScript-Array geändert. Es kann von C++ und QML gelesen und beschrieben werden
Ah, ich habe die Antwort gefunden (ich denke, nicht getestet): QQmlListProperty
In den Beispielen gibt es einige Verwendungen, z. bei qtdeclarative/examples/quick/tutorials/gettingStartedQml/filedialog/directory.*
:
Leider können Sie momentan nur schreibgeschützte Listen haben.
sie haben ein falsches Verhalten in Bezug auf QObject. Sie können einer QList übergeben werden, einfach in Form eines Zeigers, da Folgendes perfekt funktioniert:
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;
};
am besten verwenden Sie QQmlListProperty . dieses einfache Beispiel. Ich hoffe, ich helfe Ihnen .
Objekt- und Listeneigenschaften - Beispiel
Die von eatyourgreens
gegebene Antwort ist richtig. Indem Sie Ihre Klasse auf diese Weise implementieren, können Sie auf so viele Nachkommen zugreifen, wie Sie möchten. Ein weiterer hilfreicher Tipp, den ich als hilfreich empfunden habe, ist das Erstellen eines Alias für unser Modell innerhalb des qml-Delegatenelements.
ListView {
anchors.fill: parent
model: thing_manager.things
delegate: ItemDelagate {}
clip: true
spacing: 10
}
In der ItemDelegate.qml können Sie einen Alias für das Modell erstellen, um die model.modelData nicht immer zu verwenden
Item{
width: 600
height: 200
property var thing: model.modelData
Rectangle {
anchors.fill: parent
color: "red"
Text {
text: thing.name // or any other field
}
}
}
Ein sehr indirekter Weg, dies zu erreichen, ist folgender:
i.) Machen Sie ein Modell in qml
ListModel
{
id: thingModel
ListElement
{
size: 10
name: "Apple"
}
}
ii.) Stellen Sie dann ein paar Javascript-Funktionen bereit, um diese Liste zu ändern, z.
function jAppendThing( newSize, newName )
{
thingModel.append({"size": nameSize, "name": newName })
}
function jClearThing()
{
thingModel.clear()
}
ähnlich jDeleteThing etc ..
iii.) Sie können über lesen, wie Sie qml-Funktionen von c ++ aus aufrufen.
iv.) Führen Sie eine Schleife in Ihrer C++ - Liste aus und rufen Sie die Append-Funktion von qml auf, um all diese Daten ebenfalls in die qml-Liste einzufügen.
v.) Ändern Sie bei jedem Update in der C++ - Seitenliste auch die qml-Daten mit der obigen Funktion, um sie auf dem neuesten Stand zu halten.
Existiert eine gute, aber nicht erwähnte Lösung:
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;
// ...
};
Lesen und Schreiben sind anwendbar. Kein teurer Funktionsaufruf und keine Datenkopie. Einfach direkter Zugriff auf die Teilnehmer in QML:
var a = thingManager.things[0].name;
Weitere Informationen finden Sie im Dokument: https://doc-snapshots.qt.io/qt5-dev/properties.html