In diesem Artikel werden wir den C++ Teil der Anwendung zu einem vorläufigen Ende bringen. Neben dem Einsprungspunkt des Programms, werden wir auch eine Schnittstelle zum QML Interface programmieren.
Das C++ Grundgerüst war das letzte Mal noch nicht komplett fertig. Wir benötigen noch eine Klasse, die unsere Bildliste repräsentiert und als Schnittstelle zwischen Betriebssystem und QML Interface dienen soll. Dazu werden wir die Picture Klasse mittels Makro als Type für QML registrieren. Außerdem schreiben wir noch den Einsprungspunkt für unsere Anwendung. Damit bleibt für den dritten Teil nur noch der QML - Part.
Die Schnittstelle von C++ zu QML
Die Picture Klasse aus dem letzten Blog Post repräsentiert ein Bild im Speicher der Anwendung. Das Bild liegt jedoch noch nicht im Arbeitsspeicher. Es geht eigentlich darum den Speicherort und die Darstellungseigenschaften des Bildes zu manipulieren, speichern und an die QML Engine weiterzureichen. Das Laden des eigentlichen Bildes und die grafische Darstellung wird komplett von dem QML Code gesteuert. Damit QML auch weiß was eigentlich das Picture Objekt ist und was es kann, müssen wir es als Typ registrieren. Dabei hilft uns der Meta Object Compiler (MOC) und einige Macros.
Die Pictures Klasse
Sie repräsentiert eine Liste von Picture Elementen und stellt außer Methoden zum Hinzufügen, Ändern und Entfernen auch zum Speichern und Laden zur Verfügung. Zudem ist sie die Schnittstelle zu QML und im späteren Verlauf auch zu dem TCP Socket Server.
Das Q_DECLARE_METATYPE Makro lässt den MOC die Picture Klasse für den Zugriff in QML registrieren und mit dem Q_INVOKABLE Makro können dann die jeweiligen Methoden aus dem QML Kontext aufgerufen werden.
Die Implementation
Im Constructor verbinden wir drei Signale von der AsyncIO Klasse mit Slots der Pictures Klasse. Beim Erstellen kümmert sich mal wieder der Meta Object Compiler um den nötigen Boilerplate Code. Zudem wird die load() Methode aufgerufen.
Die toJsonDoc Methode und ihre überladene Schwester erstellt uns ein JSON Objekt zum Speichern und versenden der Bilddaten. Der Code Abschnitt im Lambda Ausdruck, der als Parameter von QtConcurrent::run übergeben wurde, wird in einem neuem Thread ausgeführt.
Die list() Methode gibt ein QQmlListProperty<Picture> Objekt zurück, das auf die aktuelle Instanz der Pictures Klasse und einigen ihrer Methoden verweist.
Die statischen Methoden können aus dem QML Kontext aufgerufen werden und verweisen auf die entsprechenden Methoden der instanszierten Klasse.
Diese Methoden werden später für den Server benötigt. Ihre Funktionalität entspricht den jeweiligen Namen.
Abschließend sind hier die drei Methoden, die im Constructor mit den Signalen von der AsyncIO Klasse verbunden wurden. Erwähnenswert ist allerdings einzig die onLoaded Methode. Sie erstellt aus den JSON Objekten die Datenstruktur der Bilderliste.
Einsprungpunkt der Anwendung
Für alle die jetzt ein wenig verwirrt drein Blicken; Die Main Funktion ist der Einsprungspunkt und somit die Stelle an dem die Ausführung des Programms beginnt.
In C++ wäre das int main() { /* ...* / return 0; }.
Nach dem Erstellen eines Pictures Objekts registrieren wir die Picture Klasse für den QML Kontext, damit aus diesem dann auf die Eigenschaften zugegriffen werden kann.
Danach wird je eine Instanz von QGuiApplication und QQmlApplicationEngine erzeugt. QGuiApplication ist vor allem für den Eventloop des Programms zuständig. QQmlApplicationEngine kümmert sich um das Ausführen des QML Codes.
Die setContextProperty Methode des rootContext Objekts erstellt letztendlich für QML eine Eigenschaft, die sich dort ähnlich wie ein JavaScript Objekt verhält. Der erste Parameter ist ein String für den Namen und der zweite ist ein Pointer zu unserer Pictures Instanz.