In Bereich der 3D-Messwerterfassung und -visualisierung ist mir Qt zu einem der wichtigsten Werkzeuge geworden. Geometriedaten in 3D zu verarbeiten und zu visualisieren bedeutet in der Regel, Hardware sehr effizient für Berechnungen und Visualisierung zu nutzen. Und das bedeutet direkte Kontrolle von CPU und GPU. Sprach-Werkzeuge dafür sind C++ und Shader. Qt spielt in diesem Bereich in der Industrie seine Stärken aus, besonders plattformübergreifend. Auch im automotiv-Sektor, und dieser ist bekanntermaßen einer der Motoren in der Entwicklung der IT.
Qt löst hier mehrere Probleme gleichzeitig. CPU und GPU können mit C++ und GLSL (Qt 6: Vulkan-Stil) sehr direkt programmiert werden. Der Pferdefuß: Bevor überhaupt der erste eigene Shader läuft, muss im C++-Teil erst Infrastruktur stehen, und zwar eine Menge:
- Render-/Materialobjekte sauber erzeugen
- Shader-Dateien laden oder einbinden
- Uniforms/Parameter übergeben
- Geometrieattribute passend bereitstellen
- Pipeline/Layout/Bindings konsistent halten
- Fehlerausgabe und Reloading/Debugging ermöglichen
- Backend-spezifische Anforderungen erfüllen
Und hier bietet Qt sozusagen das gemachte Nest. Sogar mit plattformunabhängiger Transparenz des Backends, ob es nun OpenGL(ES), Vulkan, Direct3D oder Metal wird. Real, nicht als verkaufter „Traum“.
Zusätzlich bringt Qt eine gute Lösung des bekannten Frontend / Backend Problems. Sprachen wie C++ sind hervorragend für Aufgaben zur hardwarenahen Programmierung geeignet, das ist auch die „Kinderstube“ von C++. Ich sage der Hardware ziemlich direkt, was sie wann wie zu tun hat.
Für das Frontend ist eine andere Denkweise erforderlich. Hier soll die Konzentration auf UI und UX liegen, daher werden andere, einfach gehaltene, deklarative Sprachen eingesetzt, die beschreiben, wie etwas aussehen bzw. reagieren soll. Die Komplexität soll hier im Gegensatz zum Backend mit Absicht verborgen werden.
Beide Welten müssen verheiratet werden. Qt bietet als Frontend-Sprache QML (Qt Modeling Language) an und verheiratet diese mit C++ vergleichsweise einfach. Basis ist JavaScript als Logik-Schicht, mit Property Bindings und „Event“-Handling.
Und hier kommt ein weiterer Vorteil von Qt: es erweitert C++ um Signale im Sinne von Objective-C. Statt klassischer Events in anderen UI-Tools baut es auf einen Signal-Slot Ansatz, umgeht damit generische Event-Objekte und ermöglicht eine direkte semantische Bedeutung ohne Event-Kaskade.
Damit sind die beiden wesentlichen Bausteine für die Verbindung von Frontend- und Backend-Welt gelegt:
- Signals
Ereignisse auslösen und auf diese reagieren - Bindings
Zustandslogik auslesen
Der Preis wird in der Umsetzung bezahlt. Damit kommen wir zum Meta-Object-System.
C++ ist kein Objective-C. Wie kommen wir also zu Signalen und Slots? Die Antwort: sie werden selbst wieder in C++ Code umgesetzt. Und nicht nur diese. Qt legt einen ganzen zusätzlichen Reflexions- und Messaging-Layer über C++, in C++ selbst wieder realisiert. Dazu dient ein Meta Object Compiler, der den Eingangs-C++ Code analysiert und zusätzlichen C++-Code generiert. Ursprünglicher und zusätzlich generierter Code werden dann zusammen kompiliert.
So genial dieser Ansatz ist, er bringt einen ganzen „Blumenstrauß“ von Eigenwilligkeiten mit sich, mit denen der Qt-Entwickler dann täglich zu kämpfen hat. So werden manche Fehler erst zur Laufzeit sichtbar und das Debugging ist durch den indirekten Call-Stack, sagen wir mal, tricky.
Weiter trennt Qt extrem strikt zwischen öffentlicher, stabiler API und beweglicher interner Implementierung, viel läuft über PIMPL (Pointer to Implementation). Wenn es kracht, steht man im Debugging vor einem nichtssagenden d-pointer. Und Qt ist hier leider eher ein Sensibelchen. Module wie BLE lassen sich sehr leicht in instabile Zustände versetzen, man kann hier sehr schnell bei der Fehlersuche an der „black box“ verzweifeln. Es ist etwas wie Magie, im Guten wie im Schlechten.
Und dennoch, ich persönlich weiß Qt immens zu schätzen. Denn dieses Framework gibt mir genau das, was in meinem Bereich zählt: direkt verzahnte Frontend- und Backend-Entwicklung bei echter plattformunabhängiger, und dennoch hardwarenaher Kontrolle, sowohl für CPU wie GPU.