QML-Erweiterungen mit C++ schreiben
Das Qt Qml Modul bietet eine Reihe von APIs zur Erweiterung von QML durch C++-Erweiterungen. Sie können Erweiterungen schreiben, um eigene QML-Typen hinzuzufügen, bestehende Qt-Typen zu erweitern oder C/C++-Funktionen aufzurufen, auf die aus normalem QML-Code nicht zugegriffen werden kann.
Dieses Tutorial zeigt, wie man eine QML-Erweiterung mit C++ schreibt, die zentrale QML-Funktionen wie Eigenschaften, Signale und Bindungen umfasst. Außerdem wird erläutert, wie Erweiterungen über Plugins bereitgestellt werden können.
Viele der in diesem Tutorial behandelten Themen sind ausführlicher in „Übersicht – QML- und C++-Integration“ und den dortigen Unterthemen dokumentiert. Insbesondere könnten die Unterthemen „Attribute von C++-Klassen für QML verfügbar machen“ und „QML-Typen aus C++ definieren“ für Sie von Interesse sein.
Öffnen der Tutorial-Quellcodes
Der Code dieses Tutorials ist als Teil der Qt-Quellcodes verfügbar. Wenn Sie Qt mit dem „ Qt Online Installer “ installiert haben, finden Sie die Quellcodes im Qt-Installationsverzeichnis unter „Examples/Qt-6.12.0/qml/tutorials/extending-qml/“.
Projekt von Grund auf erstellen
Alternativ können Sie dem Tutorial folgen, indem Sie die Quelldateien von Grund auf neu erstellen: Erstellen Sie für jedes Kapitel ein neues Projekt mithilfe der Anwendungsvorlage „Qt Quick “:
- Wenn Sie „ Qt Creator “ verwenden, befolgen Sie die Anweisungen unter Qt Creator: „ Qt Quick -Anwendungen erstellen“.
- Wenn Sie „ Qt Extension for Visual Studio Code “ verwenden, befolgen Sie die Anweisungen unter Qt Extension for Visual Studio Code: „Qt-Projekte erstellen“.
Folgen Sie dann den Anweisungen, indem Sie den generierten Skelettcode anpassen und erweitern.
Kapitel 1: Einen neuen Typ erstellen
extending-qml/chapter1-basics
Eine häufige Aufgabe bei der Erweiterung von QML ist die Bereitstellung eines neuen QML-Typs, der über die Funktionen der integrierten Elemente hinausgehende benutzerdefinierte Funktionen unterstützt Qt Quick types. Dies könnte beispielsweise dazu dienen, bestimmte Datenmodelle zu implementieren, Typen mit benutzerdefinierten Mal- und Zeichenfunktionen bereitzustellen oder auf Systemfunktionen wie Netzwerkprogrammierung zuzugreifen, die über die integrierten QML-Funktionen nicht zugänglich sind.
In diesem Tutorial zeigen wir, wie man die C++-Klassen im Modul „ Qt Quick “ nutzt, um QML zu erweitern. Das Endergebnis wird eine einfache Kreisdiagramm-Darstellung sein, die durch mehrere benutzerdefinierte QML-Typen implementiert wird, die über QML-Funktionen wie Bindungen und Signale miteinander verbunden sind und der QML Runtime über ein Plugin zur Verfügung gestellt werden.
Zunächst erstellen wir einen neuen QML-Typ namens „PieChart“, der zwei Eigenschaften besitzt: einen Namen und eine Farbe. Wir stellen ihn in einem importierbaren Typ-Namespace namens „Charts“ mit der Version 1.0 zur Verfügung.
Wir möchten, dass dieser PieChart -Typ in QML wie folgt verwendet werden kann:
import Charts
PieChart {
width: 100; height: 100
name: "A simple pie chart"
color: "red"
}Hinweis: Möglicherweise müssenSie „ QML Language Server “ und dessen semantische Hervorhebung (unter Qt Creator oder unter Qt Extension for Visual Studio Code) aktivieren, damit „ Qt Creator “ PieChart korrekt hervorhebt.
Dazu benötigen wir eine C++-Klasse, die diesen PieChart -Typ und seine Eigenschaften kapseln. Da QML das Metaobjektsystem von Qt intensiv nutzt, muss diese neue Klasse:
- von QObject
- ihre Eigenschaften mithilfe des Makros „ Q_PROPERTY “ deklarieren
Klassendeklaration
Hier ist unsere Klasse ` PieChart `, definiert in ` piechart.h`:
#include <QtQuick/QQuickPaintedItem>
#include <QColor>
class PieChart : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName FINAL)
Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
QML_ELEMENT
public:
PieChart(QQuickItem *parent = nullptr);
QString name() const;
void setName(const QString &name);
QColor color() const;
void setColor(const QColor &color);
void paint(QPainter *painter) override;
private:
QString m_name;
QColor m_color;
};Die Klasse erbt von „ QQuickPaintedItem “, da wir die Methode „ QQuickPaintedItem::paint()“ überschreiben möchten, um Zeichenoperationen mit der „ QPainter “-API durchzuführen. Würde die Klasse lediglich einen Datentyp darstellen und kein Element sein, das tatsächlich angezeigt werden muss, könnte sie einfach von „ QObject “ erben. Oder wenn wir die Funktionalität einer bestehenden, auf „ QObject “ basierenden Klasse erweitern möchten, könnte sie stattdessen von dieser Klasse erben. Alternativ können wir, wenn wir ein visuelles Element erstellen möchten, das keine Zeichenoperationen mit der „ QPainter “-API ausführen muss, einfach eine Unterklasse von „ QQuickItem “ erstellen.
Die Klasse „ PieChart “ definiert die beiden Eigenschaften „ name “ und „ color “ mit dem Makro „ Q_PROPERTY “ und überschreibt „ QQuickPaintedItem::paint()“. Die Klasse „ PieChart “ wird mit dem Makro „ QML_ELEMENT “ registriert, damit sie von QML aus verwendet werden kann. Wenn Sie die Klasse nicht registrieren, kann „ App.qml “ kein „ PieChart “ erstellen.
qmake-Einrichtung
Damit die Registrierung wirksam wird, wird die Option „ qmltypes “ zur Datei „ CONFIG “ in der Projektdatei hinzugefügt und es werden die Einträge „ QML_IMPORT_NAME “ sowie „ QML_IMPORT_MAJOR_VERSION “ angegeben:
CONFIG += qmltypes
QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1Zudem muss manuell eine qmldir-Datei hinzugefügt werden, um ein QML-Modul zu erstellen.
module Charts
typeinfo chapter1-basics.qmltypes
depends QtQuick
prefer :/qt/qml/Charts/
App 254.0 App.qmlCMake-Einrichtung
Damit die Registrierung bei Verwendung von CMake wirksam wird, verwenden Sie den Befehl ` qt_add_qml_module() `:
qt_add_qml_module(chapter1-basics
URI Charts
QML_FILES App.qml
DEPENDENCIES QtQuick
)Die API ` qt_add_qml_module() ` generiert automatisch eine Datei „ qmldir “ für das QML-Modul.
Klassenimplementierung
Die Klassenimplementierung in „ piechart.cpp “ legt lediglich die Werte für „ m_name “ und „ m_color “ entsprechend fest und gibt sie zurück sowie implementiert „ paint() “, um ein einfaches Kreisdiagramm zu zeichnen:
PieChart::PieChart(QQuickItem *parent)
: QQuickPaintedItem(parent)
{
}
...
void PieChart::paint(QPainter *painter)
{
QPen pen(m_color, 2);
painter->setPen(pen);
painter->setRenderHints(QPainter::Antialiasing, true);
painter->drawPie(boundingRect().adjusted(1, 1, -1, -1), 90 * 16, 290 * 16);
}Verwendung in QML
Nachdem wir nun den Typ „ PieChart “ definiert haben, werden wir ihn in QML verwenden. Die Datei „ App.qml “ erstellt ein „ PieChart “-Element und zeigt die Details des Kreisdiagramms mithilfe eines standardmäßigen QML-Elements „ Text “ an:
import Charts
import QtQuick
Item {
width: 300; height: 200
PieChart {
id: aPieChart
anchors.centerIn: parent
width: 100; height: 100
name: "A simple pie chart"
color: "red"
}
Text {
anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
text: aPieChart.name
}
}Beachten Sie, dass die Farbe zwar in QML als Zeichenkette angegeben wird, für die „ color “-Eigenschaft des PieChart jedoch automatisch in ein „ QColor “-Objekt umgewandelt wird. Automatische Konvertierungen werden für verschiedene andere Werttypen bereitgestellt. So kann beispielsweise eine Zeichenkette wie „640x480“ automatisch in einen „ QSize “-Wert umgewandelt werden.
Außerdem erstellen wir eine C++-Anwendung, die ein ` QQuickView ` verwendet, um ein ` App.qml` auszuführen und anzuzeigen.
Hier ist die Anwendung „ main.cpp “:
#include "piechart.h"
#include <QtQuick/QQuickView>
#include <QGuiApplication>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.loadFromModule("Charts", "App");
view.show();
return QGuiApplication::exec();
}Projekt erstellen
Um das Projekt zu erstellen, binden wir die Dateien ein, verknüpfen sie mit den Bibliotheken und definieren einen Typ-Namespace namens „Charts“ mit der Version 1.0 für alle Typen, die für QML verfügbar sind.
Verwendung von qmake:
QT += qml quick
CONFIG += qmltypes
QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1
HEADERS += piechart.h
SOURCES += piechart.cpp \
main.cpp
RESOURCES += chapter1-basics.qrc
DESTPATH = $$[QT_INSTALL_EXAMPLES]/qml/tutorials/extending-qml/chapter1-basics
target.path = $$DESTPATH
INSTALLS += targetMit CMake:
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(chapter1-basics LANGUAGES CXX)
find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick)
qt_standard_project_setup(REQUIRES 6.8)
qt_add_executable(chapter1-basics
main.cpp
piechart.cpp piechart.h
)
set_target_properties(chapter1-basics PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(chapter1-basics PUBLIC
Qt6::Core
Qt6::Gui
Qt6::Qml
Qt6::Quick
)
qt_add_qml_module(chapter1-basics
URI Charts
QML_FILES App.qml
DEPENDENCIES QtQuick
)
install(TARGETS chapter1-basics
BUNDLE DESTINATION .
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
qt_generate_deploy_qml_app_script(
TARGET chapter1-basics
OUTPUT_SCRIPT deploy_script
NO_UNSUPPORTED_PLATFORM_ERROR
DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
)
install(SCRIPT ${deploy_script})Nun können wir die Anwendung erstellen und ausführen:

Hinweis: Möglicherweise wird die Warnung „Ausdruck … hängt von nicht bindbaren Eigenschaften ab: PieChart::name“angezeigt . Dies liegt daran, dass wir eine Bindung zur beschreibbaren Eigenschaft „ name “ hinzufügen, aber noch kein „notify“-Signal dafür definiert haben. Die QML-Engine kann die Bindung daher nicht aktualisieren, wenn sich der Wert von „ name “ ändert. Dies wird in den folgenden Kapiteln behandelt.
Kapitel 2: Anbindung an C++-Methoden und -Signale
extending-qml/chapter2-methods
Angenommen, wir möchten, dass „ PieChart “ über eine Methode „clearChart()“ verfügt, die das Diagramm löscht und anschließend ein Signal „chartCleared“ aussendet. Unser „ App.qml “ könnte dann „ clearChart() “ aufrufen und Signale wie „ chartCleared() “ wie folgt empfangen:
import Charts
import QtQuick
Item {
width: 300; height: 200
PieChart {
id: aPieChart
anchors.centerIn: parent
width: 100; height: 100
color: "red"
onChartCleared: console.log("The chart has been cleared")
}
MouseArea {
anchors.fill: parent
onClicked: aPieChart.clearChart()
}
Text {
anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
text: "Click anywhere to clear the chart"
}
}
Dazu fügen wir unserer C++-Klasse eine Methode „ clearChart() “ und ein Signal „ chartCleared() “ hinzu:
class PieChart : public QQuickPaintedItem
{
...
public:
...
Q_INVOKABLE void clearChart();
signals:
void chartCleared();
...
};Durch die Verwendung von ` Q_INVOKABLE ` wird die Methode ` clearChart() ` für das Qt-Metaobjekt-System und damit auch für QML verfügbar gemacht.
Hinweis: Sie können die Methode auch als Qt-Slot deklarieren, anstatt ` Q_INVOKABLE` zu verwenden, da öffentliche und geschützte Slots ebenfalls von QML aus aufrufbar sind (private Slots können nicht aufgerufen werden).
Die Methode ` clearChart() ` ändert die Farbe in ` Qt::transparent`, zeichnet das Diagramm neu und sendet anschließend das Signal ` chartCleared() ` aus:
Wenn wir nun die Anwendung ausführen und auf das Fenster klicken, verschwindet das Kreisdiagramm, und die Anwendung gibt Folgendes aus:
qml: The chart has been clearedKapitel 3: Hinzufügen von Eigenschaftsbindungen
extending-qml/chapter3-bindings
Die Eigenschaftsbindung ist eine leistungsstarke Funktion von QML, mit der Werte unterschiedlicher Typen automatisch synchronisiert werden können. Sie nutzt Signale, um andere Typen zu benachrichtigen und deren Werte zu aktualisieren, wenn sich Eigenschaftswerte ändern.
Aktivieren wir die Eigenschaftsbindungen für die Eigenschaft „ color “. Das bedeutet, wenn wir folgenden Code haben:
import Charts
import QtQuick
Item {
width: 300; height: 200
Row {
anchors.centerIn: parent
spacing: 20
PieChart {
id: chartA
width: 100; height: 100
color: "red"
}
PieChart {
id: chartB
width: 100; height: 100
color: chartA.color
}
}
MouseArea {
anchors.fill: parent
onClicked: { chartA.color = "blue" }
}
Text {
anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter; bottomMargin: 20 }
text: "Click anywhere to change the chart color"
}
}
Die Anweisung „color: chartA.color“ bindet den Wert „ color “ von „ chartB “ an den Wert „ color “ von „ chartA “. Immer wenn sich der Wert von „ color “ bei „ chartA “ ändert, wird der Wert von „ color “ bei „ chartB “ auf denselben Wert aktualisiert. Wenn auf das Fenster geklickt wird, ändert der Handler „ onClicked “ in der Datei „ MouseArea “ die Farbe von „ chartA “, wodurch beide Diagramme die Farbe Blau annehmen.
Es ist einfach, die Eigenschaftsbindung für die Eigenschaft „ color “ zu aktivieren. Wir fügen der Deklaration „ Q_PROPERTY()“ eine NOTIFY-Funktion hinzu, um anzugeben, dass bei jeder Wertänderung ein „colorChanged“-Signal ausgesendet wird.
class PieChart : public QQuickPaintedItem
{
...
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged FINAL)
public:
...
signals:
void colorChanged();
...
};Anschließend senden wir dieses Signal in ` setColor()` aus:
void PieChart::setColor(const QColor &color)
{
if (color != m_color) {
m_color = color;
update(); // repaint with the new color
emit colorChanged();
}
}Es ist wichtig, dass „ setColor() “ vor dem Auslösen von „ colorChanged() “ überprüft, ob sich der Farbwert tatsächlich geändert hat. Dadurch wird sichergestellt, dass das Signal nicht unnötig ausgelöst wird, und es werden Endlosschleifen verhindert, wenn andere Typen auf die Wertänderung reagieren.
Die Verwendung von Bindungen ist für QML unerlässlich. Sie sollten für Eigenschaften immer NOTIFY-Signale hinzufügen, sofern diese implementiert werden können, damit Ihre Eigenschaften in Bindungen verwendet werden können. Eigenschaften, die nicht gebunden werden können, lassen sich nicht automatisch aktualisieren und können in QML nicht so flexibel genutzt werden. Da Bindungen in QML zudem sehr häufig aufgerufen werden und eine wichtige Rolle spielen, kann es bei Benutzern Ihrer benutzerdefinierten QML-Typen zu unerwartetem Verhalten kommen, wenn keine Bindungen implementiert sind.
Kapitel 4: Verwendung benutzerdefinierter Eigenschaftstypen
extending-qml/chapter4-customPropertyTypes
Der Typ „ PieChart “ verfügt derzeit über eine Eigenschaft vom Typ „string“ und eine Eigenschaft vom Typ „color“. Er könnte viele weitere Arten von Eigenschaften aufweisen. Beispielsweise könnte er eine Eigenschaft vom Typ „int“ besitzen, um eine Kennung für jedes Diagramm zu speichern:
// C++
class PieChart : public QQuickPaintedItem
{
Q_PROPERTY(int chartId READ chartId WRITE setChartId NOTIFY chartIdChanged)
...
public:
void setChartId(int chartId);
int chartId() const;
...
signals:
void chartIdChanged();
};
// QML
PieChart {
...
chartId: 100
}Neben ` int` könnten wir verschiedene andere Eigenschaftstypen verwenden. Viele der Qt-Datentypen wie ` QColor`, ` QSize ` und ` QRect ` werden von QML automatisch unterstützt. (Eine vollständige Liste finden Sie in der Dokumentation zur Datentypkonvertierung zwischen QML und C++.)
Wenn wir eine Eigenschaft erstellen möchten, deren Typ von QML standardmäßig nicht unterstützt wird, müssen wir den Typ bei der QML-Engine registrieren.
Ersetzen wir beispielsweise die Verwendung von „ property “ durch einen Typ namens „PieSlice“, der über eine Eigenschaft „ color “ verfügt. Anstatt eine Farbe zuzuweisen, weisen wir einen Wert vom Typ „ PieSlice “ zu, der wiederum eine „ color “ enthält:
import Charts
import QtQuick
Item {
width: 300; height: 200
PieChart {
id: chart
anchors.centerIn: parent
width: 100; height: 100
pieSlice: PieSlice {
anchors.fill: parent
color: "red"
}
}
Component.onCompleted: console.log("The pie is colored " + chart.pieSlice.color)
}Wie „ PieChart “ erbt auch dieser neue Typ „ PieSlice “ von „ QQuickPaintedItem “ und deklariert seine Eigenschaften mit „ Q_PROPERTY()“:
class PieSlice : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
QML_ELEMENT
public:
PieSlice(QQuickItem *parent = nullptr);
QColor color() const;
void setColor(const QColor &color);
void paint(QPainter *painter) override;
private:
QColor m_color;
};Um ihn in „ PieChart “ zu verwenden, ändern wir die Eigenschaftsdeklaration von „ color “ und die zugehörigen Methodensignaturen:
class PieChart : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(PieSlice* pieSlice READ pieSlice WRITE setPieSlice FINAL)
...
public:
...
PieSlice *pieSlice() const;
void setPieSlice(PieSlice *pieSlice);
...
};Bei der Implementierung von „ setPieSlice() “ ist eine Sache zu beachten. „ PieSlice “ ist ein visuelles Element und muss daher mithilfe von „ QQuickItem::setParentItem()“ als untergeordnetes Element von „ PieChart “ festgelegt werden, damit „ PieChart “ weiß, dass dieses untergeordnete Element beim Zeichnen seines Inhalts gerendert werden muss:
void PieChart::setPieSlice(PieSlice *pieSlice)
{
m_pieSlice = pieSlice;
pieSlice->setParentItem(this);
}Wie der Typ „ PieChart “ muss auch der Typ „ PieSlice “ mithilfe von „ QML_ELEMENT “ für QML exponiert werden.
class PieSlice : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
QML_ELEMENT
public:
PieSlice(QQuickItem *parent = nullptr);
QColor color() const;
void setColor(const QColor &color);
void paint(QPainter *painter) override;
private:
QColor m_color;
};
...Wie bei „ PieChart “ fügen wir den Typ-Namespace „Charts“ (Version 1.0) zu unserer Build-Datei hinzu:
Mit qmake:
QT += qml quick
CONFIG += qmltypes
QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1
HEADERS += piechart.h \
pieslice.h
SOURCES += piechart.cpp \
pieslice.cpp \
main.cpp
RESOURCES += chapter4-customPropertyTypes.qrc
DESTPATH = $$[QT_INSTALL_EXAMPLES]/qml/tutorials/extending-qml/chapter4-customPropertyTypes
target.path = $$DESTPATH
INSTALLS += targetMit CMake:
...
qt_add_executable(chapter4-customPropertyTypes
main.cpp
piechart.cpp piechart.h
pieslice.cpp pieslice.h
)
qt_add_qml_module(chapter4-customPropertyTypes
URI Charts
QML_FILES App.qml
DEPENDENCIES QtQuick
)
...Kapitel 5: Verwendung von Listen-Eigenschaftstypen
extending-qml/chapter5-listproperties
Derzeit kann ein ` PieChart ` nur ein einziges ` PieSlice` enthalten. Im Idealfall sollte ein Diagramm jedoch mehrere Segmente mit unterschiedlichen Farben und Größen aufweisen. Dazu könnten wir eine ` slices `-Eigenschaft definieren, die eine Liste von ` PieSlice `-Elementen akzeptiert:
pragma ComponentBehavior: Bound
import Charts
import QtQuick
Item {
width: 300; height: 200
PieChart {
id: chart
anchors.centerIn: parent
width: 100; height: 100
component Slice: PieSlice {
parent: chart
anchors.fill: parent
}
slices: [
Slice {
color: "red"
fromAngle: 0
angleSpan: 110
},
Slice {
color: "black"
fromAngle: 110
angleSpan: 50
},
Slice {
color: "blue"
fromAngle: 160
angleSpan: 100
}
]
}
}
Dazu ersetzen wir die Eigenschaft „ pieSlice “ in „ PieChart “ durch eine Eigenschaft „ slices “, die als Typ „ QQmlListProperty “ deklariert ist. Die Klasse „ QQmlListProperty “ ermöglicht die Erstellung von Listen-Eigenschaften in Typen, die für QML verfügbar sind. Wir ersetzen die Funktion „ pieSlice() “ durch eine Funktion „ slices() “, die eine Liste von Slices zurückgibt. Außerdem verwenden wir ein „ QList “, um die interne Liste der Slices als „ m_slices “ zu speichern:
class PieChart : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<PieSlice> slices READ slices FINAL)
...
public:
...
QQmlListProperty<PieSlice> slices();
private:
QString m_name;
QList<PieSlice *> m_slices;
};Obwohl die Eigenschaft „ slices “ keine zugehörige Funktion „ WRITE “ hat, ist sie aufgrund der Funktionsweise von „ QQmlListProperty “ dennoch veränderbar. In der Implementierung von „ PieChart “ implementieren wir „ PieChart::slices() “, um einen Wert für „ QQmlListProperty “ zurückzugeben:
QQmlListProperty<PieSlice> PieChart::slices()
{
return QQmlListProperty<PieSlice>(this, &m_slices);
}Dadurch werden die erforderlichen Funktionen für die Interaktion mit der Liste aus QML heraus synthetisiert. Das resultierende ` QQmlListProperty ` ist eine Ansicht der Liste. Alternativ können Sie die einzelnen Zugriffsfunktionen für die Liste manuell bereitstellen. Dies ist erforderlich, wenn Ihre Liste kein ` QList ` ist oder wenn Sie den QML-Zugriff auf Ihre Liste einschränken oder anderweitig anpassen möchten. In den meisten Fällen ist jedoch der Konstruktor, der einen „ QList “-Zeiger entgegennimmt, die sicherste und einfachste Option.
Die Klasse „ PieSlice “ wurde ebenfalls angepasst, um die Eigenschaften „ fromAngle “ und „ angleSpan “ aufzunehmen und den Ausschnitt entsprechend diesen Werten zu zeichnen. Dies ist eine einfache Anpassung, wenn Sie die vorherigen Seiten dieses Tutorials gelesen haben; daher wird der Code hier nicht gezeigt.
Kapitel 6: Ein Erweiterungs-Plugin schreiben
extending-qml/chapter6-plugins
Derzeit werden die Typen „ PieChart “ und „ PieSlice “ von „ App.qml “ verwendet, das mithilfe eines „ QQuickView “ in einer C++-Anwendung angezeigt wird. Eine alternative Möglichkeit, unsere QML-Erweiterung zu nutzen, besteht darin, eine Plugin-Bibliothek zu erstellen, um sie der QML-Engine als neues QML-Importmodul zur Verfügung zu stellen. Dadurch können die Typen „ PieChart “ und „ PieSlice “ in einem Typ-Namespace registriert werden, der von jeder QML-Anwendung importiert werden kann, anstatt diese Typen auf die Nutzung durch eine einzige Anwendung zu beschränken.
Die Schritte zum Erstellen eines Plugins werden unter „Erstellen von C++-Plugins für QML“ beschrieben. Zunächst erstellen wir eine Plugin-Klasse namens „ ChartsPlugin “. Diese ist eine Unterklasse von „ QQmlEngineExtensionPlugin “ und verwendet das Makro „ Q_PLUGIN_METADATA()“, um das Plugin beim Qt-Metaobjektsystem zu registrieren.
Hier ist die Definition von „ ChartsPlugin “ in „ chartsplugin.h “:
#include <QQmlEngineExtensionPlugin>
class ChartsPlugin : public QQmlEngineExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid)
};Anschließend konfigurieren wir die Build-Datei so, dass das Projekt als Plugin-Bibliothek definiert wird.
Mit qmake:
TEMPLATE = lib
CONFIG += plugin qmltypes
QT += qml quick
QML_IMPORT_NAME = Charts
QML_IMPORT_MAJOR_VERSION = 1
TARGET = $$qtLibraryTarget(chartsplugin)
HEADERS += piechart.h \
pieslice.h \
chartsplugin.h
SOURCES += piechart.cpp \
pieslice.cpp
DESTPATH=$$[QT_INSTALL_EXAMPLES]/qml/tutorials/extending-qml/chapter6-plugins/$$QML_IMPORT_NAME
target.path=$$DESTPATH
qmldir.files=$$PWD/qmldir
qmldir.path=$$DESTPATH
INSTALLS += target qmldir
CONFIG += install_ok # Do not cargo-cult this!
OTHER_FILES += qmldir
# Copy the qmldir file to the same folder as the plugin binary
cpqmldir.files = qmldir
cpqmldir.path = .
COPIES += cpqmldirMit CMake:
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
qt6_policy(SET QTP0001 NEW)
qt6_add_qml_module(chartsplugin
URI "Charts"
PLUGIN_TARGET chartsplugin
DEPENDENCIES QtQuick
)
target_sources(chartsplugin PRIVATE
piechart.cpp piechart.h
pieslice.cpp pieslice.h
)
target_link_libraries(chartsplugin PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Qml
Qt6::Quick
)
install(TARGETS chartsplugin
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/Charts"
LIBRARY DESTINATION "${CMAKE_INSTALL_BINDIR}/Charts"
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qmldir
DESTINATION "${CMAKE_INSTALL_BINDIR}/Charts"
)Beim Erstellen dieses Beispiels unter Windows oder Linux befindet sich das Verzeichnis „ Charts “ auf derselben Ebene wie die Anwendung, die unser neues Importmodul verwendet. Auf diese Weise findet die QML-Engine unser Modul, da der Standard-Suchpfad für QML-Importe das Verzeichnis der ausführbaren Anwendungsdatei enthält. Unter macOS wird die Plugin-Binärdatei in das Verzeichnis „ Contents/PlugIns “ im Anwendungsbundle kopiert. Bei qmake wird dieser Pfad in „ chapter6-plugins/app.pro “ festgelegt:
macos:!qtConfig(static) {
charts.files = $$OUT_PWD/Charts
charts.path = Contents/PlugIns
QMAKE_BUNDLE_DATA += charts
}Um dies zu berücksichtigen, müssen wir diesen Speicherort außerdem als QML-Importpfad in „ main.cpp “ hinzufügen:
QQuickView view;
...Das Definieren benutzerdefinierter Importpfade ist auch dann nützlich, wenn mehrere Anwendungen dieselben QML-Importe verwenden.
Die Datei „ .pro “ enthält zudem eine zusätzliche Funktion, die sicherstellt, dass die qmldir-Datei mit der Moduldefinition immer an denselben Speicherort wie die Plugin-Binärdatei kopiert wird.
Die Datei „ qmldir “ deklariert den Modulnamen und das Plugin, das durch das Modul bereitgestellt wird:
module Charts
optional plugin chartsplugin
typeinfo plugins.qmltypes
depends QtQuick
prefer :/qt/qml/Charts/Nun verfügen wir über ein QML-Modul, das in jede beliebige Anwendung importiert werden kann, vorausgesetzt, die QML-Engine weiß, wo sie es finden kann. Das Beispiel enthält eine ausführbare Datei, die „ App.qml “ lädt, wobei die Anweisung „ import Charts 1.0 “ verwendet wird. Alternativ können Sie die QML-Datei mit dem qml-Tool laden, indem Sie den Importpfad auf das aktuelle Verzeichnis setzen, damit die Datei „ qmldir “ gefunden wird:
qml -I . App.qmlDas Modul „Charts“ wird von der QML-Engine geladen, und die von diesem Modul bereitgestellten Typen stehen in jedem QML-Dokument zur Verfügung, das es importiert.
Kapitel 7: Zusammenfassung
In diesem Tutorial haben wir die grundlegenden Schritte zum Erstellen einer QML-Erweiterung gezeigt:
- Definieren Sie neue QML-Typen, indem Sie „ QObject “ unterklassen und diese mit „ QML_ELEMENT “ oder „ QML_NAMED_ELEMENT()“ registrieren.
- Fügen Sie aufrufbare Methoden mithilfe von ` Q_INVOKABLE ` oder Qt-Slots hinzu und verbinden Sie diese mit Qt-Signalen unter Verwendung der `
onSignal`-Syntax - Fügen Sie Eigenschaftsbindungen hinzu, indem Sie NOTIFY -Signale definieren
- Definieren Sie benutzerdefinierte Eigenschaftstypen, falls die integrierten Typen nicht ausreichen
- Definieren Sie Listen-Eigenschaftstypen mithilfe von QQmlListProperty
- Erstellen Sie eine Plugin-Bibliothek, indem Sie ein Qt-Plugin definieren und eine ` qmldir` -Datei schreiben
Die Dokumentation zur QML- und C++-Integration bietet einen Überblick über weitere nützliche Funktionen, die zu QML-Erweiterungen hinzugefügt werden können. Beispielsweise könnten wir Standard-Eigenschaften verwenden, um das Hinzufügen von Slices ohne die Eigenschaft „ slices “ zu ermöglichen:
PieChart {
PieSlice { ... }
PieSlice { ... }
PieSlice { ... }
}Oder von Zeit zu Zeit mithilfe von Eigenschaftswertquellen zufällig „Slices“ hinzufügen und entfernen:
PieChart {
PieSliceRandomizer on slices {}
}Hinweis: Um mehr über QML-Erweiterungen und deren Funktionen zu erfahren, folgen Sie dem Tutorial „Erstellen fortgeschrittener QML-Erweiterungen mit C++ “.
© 2026 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.