Datentypkonvertierung zwischen QML und C++

Wenn Datenwerte zwischen QML und C++ ausgetauscht werden, werden sie von der QML-Engine so konvertiert, dass sie die richtigen Datentypen für die Verwendung in QML oder C++ haben. Dies erfordert, dass die ausgetauschten Daten von einem Typ sind, der von der Engine erkannt wird.

Die QML-Engine bietet integrierte Unterstützung für eine große Anzahl von Qt C++-Datentypen. Zusätzlich können benutzerdefinierte C++-Typen im QML-Typsystem registriert werden, um sie für die Engine verfügbar zu machen.

Weitere Informationen über C++ und die verschiedenen QML-Integrationsmethoden finden Sie auf der Übersichtsseite zur C++- und QML-Integration.

Diese Seite beschreibt die von der QML-Engine unterstützten Datentypen und wie sie zwischen QML und C++ konvertiert werden.

Dateneigentum

Wenn Daten von C++ nach QML übertragen werden, bleibt das Eigentum an den Daten immer bei C++. Die Ausnahme von dieser Regel ist, wenn ein QObject von einem expliziten C++-Methodenaufruf zurückgegeben wird: In diesem Fall übernimmt die QML-Engine die Eigentümerschaft des Objekts, es sei denn, die Eigentümerschaft des Objekts wurde explizit so festgelegt, dass sie bei C++ verbleibt, indem QQmlEngine::setObjectOwnership() mit der Angabe QQmlEngine::CppOwnership aufgerufen wurde.

Zusätzlich respektiert die QML-Engine die normale QObject parent ownership Semantik von Qt C++ Objekten und wird niemals eine QObject Instanz löschen, die ein parent hat.

Grundlegende Qt-Datentypen

Standardmäßig erkennt QML die folgenden Qt-Datentypen, die automatisch in einen entsprechenden QML-Werttyp konvertiert werden, wenn sie von C++ an QML übergeben werden und umgekehrt:

Anmerkung: Klassen, die durch das Qt GUI Modul bereitgestellten Klassen, wie QColor, QFont, QQuaternion und QMatrix4x4, sind in QML nur verfügbar, wenn das Qt Quick Modul enthalten ist.

Der Einfachheit halber können viele dieser Typen in QML durch Zeichenkettenwerte oder durch eine verwandte Methode angegeben werden, die vom Objekt QtQml::Qt bereitgestellt wird. Die Eigenschaft Image::sourceSize ist beispielsweise vom Typ size (der automatisch in den Typ QSize übersetzt wird) und kann durch einen als "widthxheight" formatierten String-Wert oder durch die Funktion Qt.size() angegeben werden:

Item {
    Image { sourceSize: "100x200" }
    Image { sourceSize: Qt.size(100, 200) }
}

Weitere Informationen finden Sie in der Dokumentation für jeden einzelnen Typ unter QML-Wertetypen.

QObject-abgeleitete Typen

Jede von QObject abgeleitete Klasse kann als Typ für den Datenaustausch zwischen QML und C++ verwendet werden, sofern die Klasse im QML-Typsystem registriert wurde.

Die Engine erlaubt die Registrierung sowohl von instanzierbaren als auch von nicht instanzierbaren Typen. Sobald eine Klasse als QML-Typ registriert ist, kann sie als Datentyp für den Austausch von Daten zwischen QML und C++ verwendet werden. Weitere Einzelheiten zur Typregistrierung finden Sie unter Registrierung von C++-Typen mit dem QML-Typsystem.

Konvertierung zwischen Qt- und JavaScript-Typen

Die QML-Engine verfügt über integrierte Unterstützung für die Konvertierung einer Reihe von Qt-Typen in verwandte JavaScript-Typen und umgekehrt, wenn Daten zwischen QML und C++ übertragen werden. Dadurch ist es möglich, diese Typen zu verwenden und sie in C++ oder JavaScript zu empfangen, ohne dass benutzerdefinierte Typen implementiert werden müssen, die Zugriff auf die Datenwerte und ihre Attribute bieten.

(Beachten Sie, dass die JavaScript-Umgebung in QML die nativen JavaScript-Objektprototypen, einschließlich derer von String, Date und Number, modifiziert, um zusätzliche Funktionen zu bieten. Weitere Einzelheiten finden Sie in der JavaScript-Host-Umgebung ).

QVariantList und QVariantMap zu JavaScript Array-like und Object

Die QML-Engine bietet eine automatische Typkonvertierung zwischen QVariantList und JavaScript Array-likes sowie zwischen QVariantMap und JavaScript-Objekten.

Ein Array-like ist im Sinne von ECMAScript ein Objekt, das wie ein Array verwendet wird. Die Array-likes, die durch die Konvertierung von QVariantList (und anderen sequenziellen C++-Containern) erzeugt werden, sind nicht nur das, sondern bieten auch die üblichen Array-Methoden und synchronisieren automatisch die Längeneigenschaft. Sie können genau wie JavaScript-Arrays für alle praktischen Zwecke verwendet werden. Die Methode Array.isArray() gibt für sie allerdings immer noch false zurück.

Die unten in QML definierte Funktion erwartet beispielsweise zwei Argumente, ein Array und ein Objekt, und gibt deren Inhalt unter Verwendung der JavaScript-Standardsyntax für den Zugriff auf Arrays und Objektelemente aus. Der folgende C++-Code ruft diese Funktion auf und übergibt ein QVariantList und ein QVariantMap, die automatisch in JavaScript-Array-ähnliche bzw. Objektwerte konvertiert werden:

QML
// MyItem.qml
Item {
    function readValues(anArray, anObject) {
        for (var i=0; i<anArray.length; i++)
            console.log("Array item:", anArray[i])

        for (var prop in anObject) {
            console.log("Object item:", prop, "=", anObject[prop])
        }
    }
}
C++
// C++
QQuickView view(QUrl::fromLocalFile("MyItem.qml"));

QVariantList list;
list << 10 << QColor(Qt::green) << "bottles";

QVariantMap map;
map.insert("language", "QML");
map.insert("released", QDate(2010, 9, 21));

QMetaObject::invokeMethod(view.rootObject(), "readValues",
        Q_ARG(QVariant, QVariant::fromValue(list)),
        Q_ARG(QVariant, QVariant::fromValue(map)));

Dies erzeugt eine Ausgabe wie:

Array item: 10
Array item: #00ff00
Array item: bottles
Object item: language = QML
Object item: released = Tue Sep 21 2010 00:00:00 GMT+1000 (EST)

Wenn ein C++-Typ einen QVariantList - oder QVariantMap -Typ für einen Eigenschaftstyp oder Methodenparameter verwendet, kann der Wert als JavaScript-Array oder -Objekt in QML erstellt werden und wird automatisch in einen QVariantList - oder QVariantMap -Typ konvertiert, wenn er an C++ übergeben wird.

Seit Qt 6.5 können QVariantList Eigenschaften von C++-Typen an Ort und Stelle durch QML-Code geändert werden. Beachten Sie jedoch, dass dies nicht für QVariantMap Eigenschaften von C++-Typen gilt. Diese werden als Werte gespeichert und können nicht an Ort und Stelle durch QML-Code geändert werden. Sie können nur die gesamte Map ersetzen, aber nicht ihren Inhalt manipulieren. Der folgende Code funktioniert nicht, wenn die Eigenschaft m eine QVariantMap ist:

MyMapExposingItem {
   m: ({ one: 1 })
   Component.onCompleted: m.ten = 10
}

Der folgende Code funktioniert jedoch:

MyMapExposingItem {
   m: ({ one: 1 })
   Component.onCompleted: m = { one: 1, ten: 10 }
}

QDateTime zu JavaScript Datum

Die QML-Engine bietet eine automatische Typkonvertierung zwischen QDateTime Werten und JavaScript Date Objekten.

Die unten in QML definierte Funktion erwartet beispielsweise ein JavaScript Date Objekt und gibt ein neues Date Objekt mit dem aktuellen Datum und der Uhrzeit zurück. Der folgende C++-Code ruft diese Funktion auf und übergibt einen QDateTime -Wert, der von der Engine automatisch in ein Date -Objekt umgewandelt wird, wenn er an die Funktion readDate() übergeben wird. Im Gegenzug gibt die Funktion readDate() ein Date Objekt zurück, das automatisch in einen QDateTime Wert umgewandelt wird, wenn es in C++ empfangen wird:

QML
// MyItem.qml
Item {
    function readDate(dt) {
        console.log("The given date is:", dt.toUTCString());
        return new Date();
    }
}
C++
// C++QQuickView view(QUrl::fromLocalFile("MyItem.qml"));QDateTime dateTime = QDateTime::currentDateTime();QDateTime retValue;QMetaObject::invokeMethod(view.rootObject(), "readDate",Q_RETURN_ARG(QVariant, retValue),Q_ARG(QVariant, QVariant::fromValue(dateTime)));
qDebug() << "Value returned from readDate():" << retValue;

Ähnlich verhält es sich, wenn ein C++-Typ ein QDateTime für einen Eigenschaftstyp oder Methodenparameter verwendet. Der Wert kann als JavaScript Date Objekt in QML erstellt werden und wird automatisch in einen QDateTime Wert konvertiert, wenn er an C++ übergeben wird.

Hinweis: Achten Sie auf den Unterschied in der Monatsnummerierung: JavaScript nummeriert den Januar als 0 bis 11 für den Dezember und weicht damit um eins von der Qt-Nummerierung des Januars als 1 bis 12 für den Dezember ab.

Hinweis: Bei der Verwendung einer Zeichenkette in JavaScript als Wert eines Date -Objekts ist zu beachten, dass eine Zeichenkette ohne Zeitfelder (also ein einfaches Datum) als UTC-Beginn des betreffenden Tages interpretiert wird, im Gegensatz zu new Date(y, m, d), das den Beginn des Tages in lokaler Zeit verwendet. Die meisten anderen Möglichkeiten, ein Date -Objekt in JavaScript zu konstruieren, ergeben eine lokale Zeit, es sei denn, es werden Methoden mit UTC im Namen verwendet. Wenn Ihr Programm in einer Zone hinter UTC (nominell westlich des Nullmeridians) ausgeführt wird, führt die Verwendung einer reinen Datumszeichenkette zu einem Date Objekt, dessen getDate() um eins kleiner ist als die Tageszahl in Ihrer Zeichenkette; es wird typischerweise einen großen Wert für getHours() haben. Die UTC-Varianten dieser Methoden, getUTCDate() und getUTCHours(), liefern die Ergebnisse, die Sie für ein solches Date Objekt erwarten. Siehe auch den nächsten Abschnitt.

QDate und JavaScript Datum

Die QML-Engine konvertiert automatisch zwischen QDate und dem JavaScript-Typ Date, indem sie das Datum durch den UTC-Anfang seines Tages darstellt. Ein Datum wird über QDateTime auf QDate zurückgeführt, indem die Methode date() ausgewählt wird, wobei die lokale Zeitform des Datums verwendet wird, es sei denn, die UTC-Form des Datums fällt mit dem Beginn des nächsten Tages zusammen; in diesem Fall wird die UTC-Form verwendet.

Diese leicht exzentrische Anordnung ist ein Workaround für die Tatsache, dass JavaScript's Konstruktion eines Date -Objekts aus einer reinen Datumszeichenkette den UTC-Anfang des Tages verwendet, während new Date(y, m, d) den Ortszeit-Anfang des angegebenen Datums verwendet, wie in einem Hinweis am Ende des vorherigen Abschnitts beschrieben.

Wenn also eine Eigenschaft oder ein Parameter von QDate in QML angezeigt wird, sollte man beim Auslesen seines Wertes vorsichtig sein: Die Methoden Date.getUTCFullYear(), Date.getUTCMonth() und Date.getUTCDate() liefern mit größerer Wahrscheinlichkeit die vom Benutzer erwarteten Ergebnisse als die entsprechenden Methoden ohne UTC in ihrem Namen.

Daher ist es in der Regel robuster, eine QDateTime Eigenschaft zu verwenden. Auf diese Weise kann auf der Seite QDateTime kontrolliert werden, ob das Datum (und die Uhrzeit) in UTC oder in lokaler Zeit angegeben wird; solange der JavaScript-Code so geschrieben ist, dass er mit demselben Standard arbeitet, sollten sich Probleme vermeiden lassen.

QTime und JavaScript Datum

Die QML-Engine bietet eine automatische Typkonvertierung von QTime Werten in JavaScript Date Objekte. Da QTime -Werte keine Datumskomponente enthalten, wird eine solche nur für die Konvertierung erzeugt. Sie sollten sich also nicht auf die Datumskomponente des resultierenden Date-Objekts verlassen.

Unter der Haube erfolgt die Konvertierung von einem JavaScript Date -Objekt in QTime durch Konvertierung in ein QDateTime -Objekt (unter Verwendung der lokalen Zeit) und Aufruf der Methode time().

Sequenztyp zu JavaScript-Array

Eine allgemeine Beschreibung der Sequenztypen finden Sie unter QML Sequenztypen. Die QtQml module enthält einige Sequenztypen, die Sie vielleicht verwenden möchten.

Sie können auch eine listenartige Datenstruktur erstellen, indem Sie ein QJSValue mit QJSEngine::newArray() konstruieren. Ein solches JavaScript-Array muss nicht konvertiert werden, wenn es zwischen QML und C++ übergeben wird. Siehe QJSValue#Working With Arrays für Details zur Manipulation von JavaScript-Arrays in C++.

QByteArray zu JavaScript ArrayBuffer

Die QML-Engine bietet eine automatische Typkonvertierung zwischen QByteArray Werten und JavaScript ArrayBuffer Objekten.

Wert-Typen

Einige Wertetypen in Qt, wie z.B. QPoint, werden in JavaScript als Objekte dargestellt, die die gleichen Eigenschaften und Funktionen wie in der C++ API haben. Die gleiche Darstellung ist mit benutzerdefinierten C++-Wertetypen möglich. Um einen benutzerdefinierten Wertetyp mit der QML-Engine zu aktivieren, muss die Klassendeklaration mit Q_GADGET annotiert werden. Eigenschaften, die in der JavaScript-Darstellung sichtbar sein sollen, müssen mit Q_PROPERTY deklariert werden. In ähnlicher Weise müssen Funktionen mit Q_INVOKABLE gekennzeichnet werden. Dies gilt auch für die auf QObject basierenden C++-APIs. Zum Beispiel ist die Klasse Actor unten als Gadget annotiert und hat Eigenschaften:

class Actor
{
    Q_GADGET
    Q_PROPERTY(QString name READ name WRITE setName)
public:
    QString name() const { return m_name; }
    void setName(const QString &name) { m_name = name; }

private:
    QString m_name;
};

Q_DECLARE_METATYPE(Actor)

Das übliche Muster ist, eine Gadget-Klasse als Typ einer Eigenschaft zu verwenden oder ein Gadget als Signalargument auszugeben. In solchen Fällen wird die Gadget-Instanz als Wert zwischen C++ und QML übergeben (weil es ein Wertetyp ist). Wenn QML-Code eine Eigenschaft einer Gadget-Eigenschaft ändert, wird das gesamte Gadget neu erstellt und an den C++-Eigenschaftssetzer zurückgegeben. In Qt 5 können Gadget-Typen nicht durch direkte Deklaration in QML instanziiert werden. Im Gegensatz dazu kann eine QObject Instanz deklariert werden; und QObject Instanzen werden immer per Zeiger von C++ an QML übergeben.

Aufzählungstypen

Um eine benutzerdefinierte Aufzählung als Datentyp zu verwenden, muss ihre Klasse registriert werden und die Aufzählung muss auch mit Q_ENUM() deklariert werden, um sie im Meta-Objektsystem von Qt zu registrieren. Zum Beispiel hat die Klasse Message unten eine Aufzählung Status:

class Message : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Status status READ status NOTIFY statusChanged)
public:
    enum Status {
        Ready,
        Loading,
        Error
    };
    Q_ENUM(Status)
    Status status() const;
signals:
    void statusChanged();
};

Wenn die Klasse Message im QML-Typsystem registriert wurde, kann die Enumeration Status in QML verwendet werden:

Message {
     onStatusChanged: {
         if (status == Message.Ready)
             console.log("Message is loaded!")
     }
 }

Um eine enum als flags Typ in QML zu verwenden, siehe Q_FLAG().

Hinweis: Die Namen von Enum-Werten müssen mit einem Großbuchstaben beginnen, um von QML aus zugänglich zu sein.

...
enum class Status {
          Ready,
          Loading,
          Error
}
Q_ENUM(Status)
...

Enum-Klassen werden in QML als scoped und unscoped properties registriert. Der Wert Ready wird unter Message.Status.Ready und Message.Ready registriert.

Bei der Verwendung von Enum-Klassen kann es mehrere Enums mit denselben Bezeichnern geben. Die nicht abgedeckte Registrierung wird durch die zuletzt registrierte Enum überschrieben. Für Klassen, die solche Namenskonflikte enthalten, ist es möglich, die unskopierte Registrierung zu deaktivieren, indem Sie Ihre Klasse mit einem speziellen Q_CLASSINFO Makro versehen. Verwenden Sie den Namen RegisterEnumClassesUnscoped mit dem Wert false, um zu verhindern, dass skopierte Enums im gleichen Namensraum zusammengeführt werden.

class Message : public QObject
    {
        Q_OBJECT
        Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
        Q_ENUM(ScopedEnum)
        Q_ENUM(OtherValue)

    public:
        enum class ScopedEnum {
              Value1,
              Value2,
              OtherValue
        };
        enum class OtherValue {
              Value1,
              Value2
        };
    };

Enums von verwandten Typen werden normalerweise im Geltungsbereich des verwandten Typs registriert. Zum Beispiel führt jede Enum eines anderen Typs, die in einer Q_PROPERTY Deklaration verwendet wird, dazu, dass alle Enums dieses Typs in QML verfügbar gemacht werden. Dies ist in der Regel eher eine Belastung als ein Vorteil. Um dies zu verhindern, kommentieren Sie Ihre Klasse mit einem speziellen Q_CLASSINFO Makro. Verwenden Sie den Namen RegisterEnumsFromRelatedTypes mit dem Wert false, um zu verhindern, dass Enums von verwandten Typen in diesem Typ registriert werden.

Sie sollten die umschließenden Typen aller Enums, die Sie in QML verwenden wollen, explizit registrieren, indem Sie QML_ELEMENT oder QML_NAMED_ELEMENT verwenden, anstatt sich darauf zu verlassen, dass ihre Enums in andere Typen injiziert werden.

class OtherType : public QObject
{
    Q_OBJECT
    QML_ELEMENT

public:
    enum SomeEnum { A, B, C };
    Q_ENUM(SomeEnum)

    enum AnotherEnum { D, E, F };
    Q_ENUM(AnotherEnum)
};

class Message : public QObject
{
    Q_OBJECT
    QML_ELEMENT

    // This would usually cause all enums from OtherType to be registered
    // as members of Message ...
    Q_PROPERTY(OtherType::SomeEnum someEnum READ someEnum CONSTANT)

    // ... but this way it doesn't.
    Q_CLASSINFO("RegisterEnumsFromRelatedTypes", "false")

public:
    OtherType::SomeEnum someEnum() const { return OtherType::B; }
};

Der wichtige Unterschied ist der Geltungsbereich für die Enums in QML. Wenn eine Enum aus einer verwandten Klasse automatisch registriert wird, ist der Geltungsbereich der Typ, in den sie importiert wird. Im obigen Fall würden Sie ohne das zusätzliche Q_CLASSINFO zum Beispiel Message.A verwenden. Wenn der C++-Typ, der die Enums enthält, explizit registriert ist und die Registrierung von Enums aus verwandten Typen unterdrückt wird, ist der QML-Typ für den C++-Typ, der die Enums enthält, der Geltungsbereich für alle seine Enums. Sie würden in QML OtherType.A statt Message.A verwenden.

Beachten Sie, dass Sie QML_FOREIGN verwenden können, um einen Typ zu registrieren, den Sie nicht ändern können. Sie können auch QML_FOREIGN_NAMESPACE verwenden, um die Aufzählungszeichen eines C++-Typs in einem QML-Namensraum mit einem beliebigen Namen in Großbuchstaben zu registrieren, selbst wenn derselbe C++-Typ auch als QML-Wertetyp registriert ist.

Aufzählungstypen als Signal- und Methodenparameter

C++-Signale und -Methoden mit Parametern vom Aufzählungstyp können von QML aus verwendet werden, sofern die Aufzählung und das Signal oder die Methode in derselben Klasse deklariert sind oder der Aufzählungswert einer der in Qt Namespace deklarierten Werte ist.

Wenn ein C++-Signal mit einem Enum-Parameter mit einer QML-Funktion unter Verwendung der connect() -Funktion verbunden werden soll, muss der Enum-Typ außerdem mit qRegisterMetaType() registriert werden.

Für QML-Signale können Enum-Werte als Signalparameter unter Verwendung des int -Typs übergeben werden:

Message {
    signal someOtherSignal(int statusValue)

    Component.onCompleted: {
        someOtherSignal(Message.Loading)
    }
}

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.