Qt 5.15 bietet eine stark verbesserte Möglichkeit, C++-Typen für QML darzustellen. Jetzt können Sie den Namen und die Version Ihres Moduls an einer zentralen Stelle angeben und müssen keine Nebenversionen oder Revisionen mehr angeben. Darüber hinaus können die Besonderheiten der QML-Typregistrierung jetzt in einer C++-Klassendeklaration deklariert werden.
Bisher war ein üblicher Weg, C++-Typen in QML verfügbar zu machen, die Verwendung der im Header qqml.h bereitgestellten Registrierungsfunktionen: qmlRegisterType(), qmlRegisterSingletonType(), qmlRegisterUncreatableType() usw. Dieser Ansatz hat seine Nachteile:
Sie sollten Ihre Typregistrierungen immer mit den tatsächlichen Typen synchron halten. Dies ist besonders mühsam, wenn Sie Revisionen verwenden, um Eigenschaften über verschiedene Importversionen hinweg verfügbar zu machen. Selbst wenn dies nicht der Fall ist, ist die Tatsache, dass Sie die Registrierung getrennt vom Typ angeben müssen, umständlich, da Sie leicht den Überblick verlieren können, wie Sie welche Typen in welchen Modulen registriert haben.
Da Sie Ihre Typen außerdem prozedural registrieren, kann kein QML-Tool automatisch bestimmen, welche Typen in welchen Importen verfügbar sind. Qt Creator verfügt zwar über einige Heuristiken, die versuchen, allgemeine Protokollierungsmuster in C++-Code zu erkennen, aber dies ist unvollständig. Herauszufinden, ob ein Programm eine bestimmte Registrierung durchführt, ist gleichbedeutend mit der Lösung des Stoppproblems. Einfachere Tools wie qmllint oder qmlformat kennen den C++-Code nicht und müssen Ihren QML-Code isoliert parsen. Daher haben sie keine Informationen über Typen, die in C++ registriert sind. Um dieses Problem (teilweise) zu lösen, wurden "qmltypes"-Dateien eingeführt. Bei der Entwicklung eines QML-Plugins wird empfohlen, eine Datei mit dem Namen "plugins.qmltypes" neben der Plugin-Binärdatei zu platzieren. Die qmltypes-Datei enthält Metainformationen zu den vom Plug-in registrierten Typen. Qt Creator und andere Tools können dann auf diese Informationen zurückgreifen, um Ihnen eine bessere Analyse Ihres Codes zu ermöglichen. Es funktioniert, aber nur für Plugins. Wenn Sie Ihre Typen direkt aus dem Hauptprogramm registrieren, stoßen Sie immer noch auf das gleiche Problem. Außerdem spezifizieren Sie Ihre Typen am Ende zweimal, einmal in C++ und einmal im qmltypes-Format. Um das Problem der redundanten Typangabe (teilweise) zu lösen, steht ein Tool namens „qmlplugindump“ zur Verfügung. Dieses Tool lädt Ihr Plugin genau wie die QML-Engine. Anschließend extrahiert es Informationen über alle enthaltenen Typen, um eine plugins.qmltypes-Datei zu erstellen. Dadurch kann auch nicht verwandter Code in Ihrem Plugin ausgeführt werden, und es funktioniert nur, wenn Sie Ihr Plugin für dieselbe Plattform kompilieren, auf der qmlplugindump ausgeführt wird. In der Praxis funktioniert dies nicht für übergreifend kompilierte Builds.
Angesichts all dieser Stolpersteine wurde das Typregistrierungssystem in Qt 5.15 neu gestaltet. Sie sollten qmlRegisterType() und Co. nicht mehr prozedural aufrufen. Stattdessen wird in qqml.h eine Reihe von Makros bereitgestellt, die Sie zu Klassendeklarationen hinzufügen können. Diese Makros markieren den Typ als nach QML exportiert. Das wichtigste davon ist "QML_ELEMENT". Es bietet eine Wrapper-Klasse in QML als Element, das nach der C++-Klasse benannt ist. Der Meta Object Compiler (moc) findet die so angegebenen Informationen. Wenn die Option „--output-json“ übergeben wird, stellt sie eine JSON-Datei bereit, die alle Metatypinformationen maschinenunabhängig und lesbar enthält. Sie können dieses Verhalten auslösen, indem Sie in Ihrer qmake-Projektdatei "CONFIG += metatypes" angeben. Ein neues Tool namens "qmltyperegistrar" liest dann diese Metatypdatei und möglicherweise zugehörige Dateien und generiert eine C++-Datei, die eine Funktion enthält, die alle mit den entsprechenden Makros markierten Typen registriert, sowie eine qmltypes-Datei mit nur Typinformationen, die für das definierte QML-Modul relevant sind Ihre Bewerbung. Dazu muss es den Modulnamen und die Hauptversion kennen. Sie können dies in der qmake-Projektdatei mit den Variablen "QML_IMPORT_NAME" und "QML_IMPORT_MAJOR_VERSION" angeben. Es wird keine Unterversion angegeben. qmltyperegistrar findet feste Eigenschaften und Methoden in den Metatypdaten und registriert entsprechend verschiedene Versionen des Typs. Dies bestimmt die Unterversionen unter der das Modul verfügbar ist Sie können einen Typ auch ab einer bestimmten Unterversion verfügbar machen, indem Sie das Makro "QML_ADDED_IN_MINOR_VERSION(x)" hinzufügen.
Sobald das Build-System auf diese Weise eingerichtet ist, können Sie die eigentliche Registrierung initiieren, indem Sie "CONFIG += qmltypes" hinzufügen. Der CONFIG-Parameter "qmltypes" impliziert "Metatypen". Sie müssen nicht beide angeben.
Diese Art der statischen C++-Typregistrierung für QML generiert nicht nur qmltypes-Dateien für Plugins, sondern auch für Ihre Hauptanwendung. Die letzteren Dateien heißen „app.qmltypes“ und sollten neben Ihrer Anwendungsbinärdatei platziert werden, genauso wie „plugins.qmltypes“ neben dem Plugin platziert werden sollte, auf das es sich bezieht.
Konvertieren wir zur Veranschaulichung eine Anwendung, die Typen dynamisch registriert, in eine Anwendung, die dieselben Typen statisch registriert. Dies wurde bereits mit allen QML- und QtQuick-Beispielen durchgeführt. Schauen wir uns ein einfaches Beispiel zum „Hinzufügen von Typen“ an. In Qt 5.14 und früher hatte das Beispiel die folgende Codezeile in der Datei main.cpp:
qmlRegisterType<Person>("People", 1,0, "Person");
Dadurch kann die C++-Klasse „Person“ als QML-Element, auch „Person“ genannt, im „People“-Modul in Version 1.0 registriert werden. Diese Zeile ist in Qt 5.15 verschwunden. Stattdessen wurden die folgenden Zeilen zur Datei „adding.pro“ hinzugefügt:
CONFIG += qmltypes QML_IMPORT_NAME = People QML_IMPORT_MAJOR_VERSION = 1
Diese Zeilen geben den Importnamen und die Hauptversion für alle in QML dargestellten Typen an. Die wichtigste Änderung schließlich ist das Makro „QML_ELEMENT“, das der Datei person.h hinzugefügt wurde:
class Person : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(int shoeSize READ shoeSize WRITE setShoeSize) QML_ELEMENT public: Person(QObject *parent = nullptr); [...] };
Dieses "QML_ELEMENT" weist qmltyperegistrar an, den Typ zu registrieren. Das ist alles. Jetzt können Sie so viele „QML_ELEMENT“ angeben, wie Sie möchten, ohne jedes Mal Versions- und Revisionsimportnamen eingeben zu müssen.
У меня вот возник вопрос, как понимаю adding.pro дял добавления макросов это проектный файл?
А есть проект использует cmake, как там с этим обстоит?
Скорее всего также, как и для установки всех остальных переменых в CMake, через использование set