Kapitel 60. Qt Quick und C++

Dieses Kapitel zeigt, wie man zwei Welten so verbindet, dass sie sich gegenseitig verstärken. Hier erfahren Sie: wie Entwicklungsgeschwindigkeit und Architekturqualität wachsen, wenn QML für das Visuelle und C++ für das „Gehirn” der Anwendung zuständig ist – und alles richtig verbunden ist, ohne Krücken.

Es werden 3 bewährte Integrationswege gezeigt – Einbettung von QML über QQuickWidget, Steuerung von Properties und Funktionsaufrufen über setProperty()/QMetaObject::invokeMethod(), sowie die Brücke „QML-Signale → C++-Slots” über QQmlApplicationEngine. Außerdem – Veröffentlichung von C++-Objekten über QQmlContext, Registrierung von Typen mit qmlRegisterType<T>(), Q_PROPERTY und Q_INVOKABLE, und sogar die Erweiterung von QML mit einem eigenen visuellen Element basierend auf QQuickPaintedItem.

Falls es bisher so schien, dass „QML und C++ nicht richtig zusammenarbeiten” – dieses Kapitel sollte man besser nicht überspringen.

Das Kapitel enthält Code-Beispiele, die sofort einsatzbereit sind.

Selbstüberprüfung zum Kapitel

Warum kann die Klasse QQuickWidget als normales Widget in Qt/C++-Anwendungen verwendet werden?Antwort
Richtige Antwort: QQuickWidget erbt von QWidget, daher kann es an beliebiger Stelle in einer Qt/C++-Anwendung platziert werden, unter Verwendung von Layouts oder direkter Positionierung.
Warum wird einem QML-Element die Property objectName zugewiesen, bevor man aus C++ damit interagiert?Antwort
Richtige Antwort: Der objectName ermöglicht es, das QML-Element über die Methode findChild() zu finden, da die Basisklasse QQuickItem von QObject erbt und diese Property zur Identifikation von Objekten unterstützt.
Warum wird beim Aufrufen von QML-Funktionen aus C++ der Typ QVariant für alle Argumente verwendet?Antwort
Richtige Antwort: QVariant bietet ein universelles Typsystem zwischen C++ und der JavaScript-Umgebung von QML, das eine sichere Übergabe verschiedener Datentypen über das Meta-Object-System von Qt ermöglicht.
Warum wird beim Verbinden von QML-Signalen mit C++-Slots die alte Syntax SIGNAL()/SLOT() verwendet und nicht die neue?Antwort
Richtige Antwort: QML-Objekte werden dynamisch zur Laufzeit erstellt, ihre Signale sind nur zur Runtime bekannt, während die neue Syntax eine strikte Typprüfung zur Compile-Zeit erfordert.
Was passiert, wenn man Context-Properties über setContextProperty() nach dem Laden der QML-Datei setzt?Antwort
Richtige Antwort: Beim ersten Zugriff auf diese Properties in QML tritt der Fehler “ReferenceError: property is not defined” auf, da QML versucht, auf noch nicht existierende Context-Properties zuzugreifen.
Was ist der Unterschied zwischen der Veröffentlichung eines Objekts über setContextProperty() und der Registrierung einer Klasse über qmlRegisterType()?Antwort
Richtige Antwort: setContextProperty veröffentlicht eine konkrete Objektinstanz zur Verwendung in QML, während qmlRegisterType die Klasse selbst registriert und es ermöglicht, Instanzen direkt im QML-Code zu erstellen.
Warum ist die Property result in der Klasse Calculation nur mit READ deklariert und nicht mit WRITE?Antwort
Richtige Antwort: Es handelt sich um einen berechneten Output-Wert, der nicht von außen geändert werden sollte; sein Wert wird automatisch aktualisiert, wenn sich input über die Methode setInputValue() ändert.
Wozu dient der Parameter NOTIFY in Q_PROPERTY und wann muss er zwingend verwendet werden?Antwort
Richtige Antwort: NOTIFY verknüpft die Property mit einem Signal, das über Wertänderungen benachrichtigt. Dies ist notwendig für die automatische Aktualisierung von QML-Bindings, wenn sich die Property aus C++ ändert.
Welches Problem löst die Verwendung von QQuickPaintedItem anstelle der direkten Vererbung von QQuickItem?Antwort
Richtige Antwort: QQuickPaintedItem bietet eine fertige paint()-Methode mit einem QPainter-Objekt, was die Implementierung visueller Elemente vereinfacht, ohne mit Low-Level-OpenGL-Rendering arbeiten zu müssen.
Wie greift man in QML auf ein Bild zu, das über QQuickImageProvider erstellt wird?Antwort
Richtige Antwort: Über ein spezielles URL-Schema der Form “image://provider_name/parameter”, wobei der Provider-Name bei der Registrierung über addImageProvider() festgelegt wird und die Parameter an die Methode requestImage() übergeben werden.
Warum ist die Deklaration Q_INVOKABLE notwendig, um C++-Methoden aus QML aufzurufen?Antwort
Richtige Antwort: Q_INVOKABLE fügt Informationen über die Methode zum Meta-Object-System von Qt hinzu, macht sie über QMetaObject::invokeMethod() verfügbar und für die QML-Engine zur Laufzeit sichtbar.
Was passiert, wenn mehrere QQmlApplicationEngine-Objekte in einer Anwendung erstellt werden?Antwort
Richtige Antwort: Jede Engine erstellt eine separate QML-Laufzeitumgebung mit eigenem Kontext und Zustand, was zu Ressourcen-Duplizierung und erschwerter Anwendungsverwaltung führen kann.
Wann sollte man QQuickWidget verwenden und wann QQmlApplicationEngine?Antwort
Richtige Antwort: QQuickWidget wird verwendet, um QML in Widget-basierte Qt-Anwendungen einzubetten; QQmlApplicationEngine – für vollständig QML-basierte Anwendungen mit eigenem Hauptfenster und Event-Loop.
Warum wird in der paint()-Methode der Klasse Ellipse Qt::NoPen gesetzt?Antwort
Richtige Antwort: Dies deaktiviert das Zeichnen der Konturlinie der Ellipse und belässt nur die Farbfüllung, was den Design-Anforderungen des Elements ohne Umrandung entspricht.
Welchen Vorteil bietet die Trennung von Logik in C++ und Interface in QML in der Anwendungsarchitektur?Antwort
Richtige Antwort: Es werden die Stärken beider Werkzeuge genutzt: Performance und Typsicherheit von C++ für die Business-Logik plus Deklarativität und Animationsmöglichkeiten von QML für die UI, was Entwicklung und Wartung vereinfacht.

Praktische Aufgaben

Einfaches Level

QML-Rechner mit C++-Logik
Erstellen Sie eine einfache Qt-Anwendung, bei der das Interface mit zwei Eingabefeldern und einem Button in QML implementiert ist, während die Addition zweier Zahlen in einer C++-Klasse durchgeführt wird. Beim Drücken des Buttons soll das Ergebnis in einem QML-Text-Element angezeigt werden. Verwenden Sie setContextProperty zur Veröffentlichung des C++-Objekts.
Hinweise: Erstellen Sie eine Calculator-Klasse mit einer Q_INVOKABLE-Methode add(int a, int b). Verwenden Sie QQuickWidget oder QQmlApplicationEngine zum Laden von QML. In QML verwenden Sie TextField für die Eingabe und Button für den Methodenaufruf. Vergessen Sie nicht, die Module quickwidgets oder quick/qml in der .pro-Datei einzubinden.
Mittleres Level

Bidirektionale Synchronisation einer Aufgabenliste
Implementieren Sie eine Anwendung mit einer Aufgabenliste (To-Do List), bei der das Datenmodell QStringListModel in C++ erstellt wird, während das Interface mit ListView und der Möglichkeit zum Hinzufügen/Löschen von Elementen in QML liegt. Sorgen Sie für bidirektionale Synchronisation: Änderungen in QML sollten das C++-Modell aktualisieren und umgekehrt. Fügen Sie einen Button in C++ hinzu, der programmatisch eine neue Aufgabe zur Liste hinzufügt.
Hinweise: Erstellen Sie eine TaskManager-Klasse mit Q_PROPERTY für das Modell und Q_INVOKABLE-Methoden addTask/removeTask. Verwenden Sie NOTIFY-Signale für die automatische Aktualisierung der ListView. In QML verwenden Sie einen Delegate mit Löschen-Button. Zum Hinzufügen aus C++ können Sie QPushButton im Haupt-Widget verwenden.
Schwieriges Level

Graphen-Visualisierer mit dynamischen Daten
Erstellen Sie eine Anwendung zur Visualisierung mathematischer Funktionen: Eine C++-Klasse sollte Graphenpunkte berechnen (z.B. sin, cos, tan) und sie über QQuickImageProvider oder QQuickPaintedItem an QML übergeben. Das QML-Interface sollte Steuerelemente zur Auswahl der Funktion, des Bereichs und der Skalierung enthalten. Implementieren Sie eine flüssige Animation bei Parameteränderungen und die Möglichkeit, den Graphen als Bild zu exportieren.
Hinweise: Leiten Sie von QQuickPaintedItem ab, um den Graphen über QPainter zu zeichnen. Erstellen Sie Q_PROPERTY für Funktionstyp, X/Y-Bereich und Skalierung mit NOTIFY-Signalen. In der paint()-Methode berechnen Sie Punkte und zeichnen eine Polylinie. Verwenden Sie QPropertyAnimation in QML für flüssige Übergänge. Für den Export verwenden Sie die grabToImage()-Methode des QML-Elements oder QPixmap::save() in C++.

💬 Zur Diskussion einladen!

Haben Sie verstanden, wie man die Kraft von C++ mit der Eleganz von QML verbindet? Haben Sie Fragen zur Initialisierungsreihenfolge oder zur Arbeit mit Q_PROPERTY?

Teilen Sie Ihre Erfahrungen bei der Integration, berichten Sie über aufgetretene Probleme oder helfen Sie anderen Lesern, die Interaktion zwischen C++ und QML zu meistern!

Ihre praktische Erfahrung kann ein unschätzbarer Tipp für Entwicklerkollegen sein

Leave a Reply

Your email address will not be published. Required fields are marked *