Kapitel 52. JavaScript-Unterstützungsklassen und praktische Beispiele

Sind Sie schon auf die Situation gestoßen, dass eine C++-Anwendung bereits geschrieben ist, Sie dem Benutzer aber mehr Freiheit geben möchten – ohne Neukompilierung und komplexe Plugin-Systeme? Jeder Entwickler hat sich mindestens einmal dabei ertappt zu denken: „Lass uns mal starten – dann sehen wir schon”, in der Hoffnung, dass die Verhaltenslogik doch flexibel genug sein wird.

Dieses Kapitel führt behutsam zu einer unerwarteten, aber mächtigen Lösung. Hier wird aufgedeckt, wie Qt es ermöglicht, JavaScript direkt in eine C++-Anwendung einzubetten und statischen Code in eine steuerbare Umgebung zu verwandeln. Sie werden entdecken, warum professionelle Entwickler Skripte nicht für „Spielereien” verwenden, sondern zur Beschleunigung von Entwicklung, Tests und Experimenten mit der Interface-Logik.

Im Fokus stehen QJSEngine und QJSValue, die Verbindung von Signalen und Slots mit JavaScript, die Erweiterung von Qt-Objekten „on the fly” und ein praktisches Beispiel mit „Schildkröten”-Grafik. Ein paar Dutzend Zeilen Skript – und das Ergebnis erscheint sofort, ohne Projekt-Rebuild.

Wenn Sie aufhören wollen, „auf gut Glück” zu schreiben und anfangen möchten, das Verhalten Ihrer Anwendung bewusst zu steuern, sollten Sie dieses Kapitel nicht aufschieben.

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

Selbsttest zum Kapitel

Welche Qt6-Klasse repräsentiert eine Umgebung zur Ausführung von JavaScript-Code und warum wird mindestens ein Objekt davon benötigt?Antwort
Richtige Antwort: Die Klasse QJSEngine stellt die JavaScript-Laufzeitumgebung bereit; ohne sie ist es unmöglich, Skripte zu interpretieren und auszuführen, da sie den Ausführungskontext verwaltet und die API für die Interaktion bereitstellt.
Wozu stellt die Klasse QJSValue Methoden der Familie isT() und toT() bereit?Antwort
Richtige Antwort: Die isT()-Methoden ermöglichen die Bestimmung des JavaScript-Werttyps, während toT() ihn zum gewünschten C++-Typ konvertiert, was eine sichere Interaktion zwischen den beiden Sprachen gewährleistet.
Warum gibt die Methode evaluate() QJSValue zurück, anstatt nur Code auszuführen?Antwort
Richtige Antwort: Der zurückgegebene QJSValue enthält das Ergebnis der Skriptausführung oder Fehlerinformationen, sodass der C++-Code den Erfolg mit der Methode isError() überprüfen und das Ergebnis verarbeiten kann.
Wozu wird die Methode newQObject() bei der Arbeit mit Qt-Objekten aus JavaScript benötigt?Antwort
Richtige Antwort: Die Methode erstellt einen JavaScript-Wrapper um ein Qt-Objekt und macht dessen Properties, Signale und Slots über das Qt-Meta-Objektsystem für JavaScript-Code zugänglich.
Warum ist es im Beispiel mit der Schildkröten-Grafik notwendig, setObjectName() für alle Widgets aufzurufen?Antwort
Richtige Antwort: Der festgelegte Objektname ermöglicht den Zugriff aus JavaScript-Code über einen verständlichen Identifier, nachdem er über setProperty() im globalObject() registriert wurde.
Warum wird nach jedem Zeichenbefehl in der Klasse Turtle die Methode repaint() aufgerufen?Antwort
Richtige Antwort: Der Aufruf von repaint() zeichnet das Widget sofort neu und zeigt das Ergebnis des Befehls auf dem Bildschirm; ohne dies würden sich Änderungen ansammeln und erst nach Abschluss des gesamten Skripts angezeigt werden.
Wie können JavaScript-Funktionen mit Qt-Signalen verbunden werden und wie unterscheidet sich dies vom üblichen C++-Ansatz?Antwort
Richtige Antwort: JavaScript-Funktionen werden über die connect()-Methode des Signals direkt mit Funktionen oder Methoden von Skript-Objekten verbunden; dies ermöglicht dynamische Verhaltensänderungen ohne Neukompilierung, im Gegensatz zu statischen C++-Verbindungen.
Was passiert, wenn man das Ergebnis von evaluate() nicht mit der Methode isError() überprüft?Antwort
Richtige Antwort: Skript-Ausführungsfehler bleiben unbemerkt, die Anwendung kann fehlerhaft arbeiten oder erwartete Aktionen nicht ausführen, und der Benutzer erhält keine Informationen über das Problem.
Wie kann man die Funktionalität eines Qt-Objekts mit neuen Methoden direkt aus JavaScript erweitern?Antwort
Richtige Antwort: Man kann neue Methoden zum Objekt hinzufügen, indem man Funktionen seinen Properties zuweist (z.B. turtle.circle = function(){…}), wie im Beispiel zum Zeichnen eines Kreises gezeigt.
Welche vier Möglichkeiten zur Verbindung eines Signals mit JavaScript werden im Beispiel gezeigt und worin besteht ihr Unterschied?Antwort
Richtige Antwort: Ein Signal kann verbunden werden mit: (1) einer Skriptfunktion, (2) einer Methode eines JavaScript-Klassenobjekts, (3) einem Qt-Widget-Slot direkt, (4) einer anonymen Funktion direkt in connect(). Die Wahl hängt von der Notwendigkeit der Zustandsspeicherung und Code-Wiederverwendung ab.
Warum eine separate JSTools-Klasse mit Funktionen erstellen anstatt die Qt-API direkt zu verwenden?Antwort
Richtige Antwort: JSTools bietet ein bequemes High-Level-Interface für JavaScript, verbirgt die Komplexität der Qt-API und schafft eine für Webentwickler vertraute Umgebung (alert, print usw.).
Warum sind für die Arbeit mit der Skriptsprache alle Funktionen in JSTools als Slots deklariert?Antwort
Richtige Antwort: Nur Qt-Slots sind über das Meta-Objektsystem zugänglich und können aus JavaScript aufgerufen werden, nachdem das Objekt über newQObject() registriert wurde; normale C++-Methoden sind für Skripte nicht zugänglich.
Was macht die Methode globalObject() und warum sollten Properties genau darin gesetzt werden?Antwort
Richtige Antwort: globalObject() gibt den globalen JavaScript-Umgebungskontext zurück; das Setzen von Properties darin macht Objekte und Variablen im gesamten Skript-Programm zugänglich, ohne zusätzliche Parameterübergabe.
Wie wird im Beispiel mit der Schildkröten-Grafik der Operator let anstelle von var verwendet und warum ist das wichtig?Antwort
Richtige Antwort: Der Operator let erstellt Variablen mit Block-Scope und entspricht modernen ECMAScript-Standards, verhindert Fehler durch Variable Leaking außerhalb von Schleifen und Bedingungen.

Praktische Aufgaben

Einfaches Level

Taschenrechner mit JavaScript
Erstellen Sie eine Qt-Anwendung mit zwei Textfeldern zur Zahleneingabe, einer Dropdown-Liste zur Auswahl der Operation (+, -, *, /) und einer Schaltfläche “Berechnen”. Beim Klicken auf die Schaltfläche soll ein JavaScript-Skript ausgeführt werden, das die Werte aus den Feldern nimmt, die Operation durchführt und das Ergebnis in einem Label (QLabel) ausgibt. Verwenden Sie QJSEngine zur Ausführung der Berechnungen.
Hinweise: Erstellen Sie QJSEngine und übergeben Sie ihm die Widgets über newQObject(). Erstellen Sie einen String mit einem JavaScript-Ausdruck (z.B. “10 + 5”) und führen Sie ihn über evaluate() aus. Konvertieren Sie das Ergebnis mit der toString()-Methode in einen String. Vergessen Sie nicht, Fehler über isError() zu überprüfen.
Mittleres Level

Zeichnen von Formen mit JavaScript
Erweitern Sie das Schildkröten-Grafik-Beispiel um die Möglichkeit, Stiftfarbe und Linienstärke zu steuern. Erstellen Sie JavaScript-Funktionen setColor(r, g, b) und setWidth(width), die QPainter-Parameter ändern. Implementieren Sie fertige Skripte zum Zeichnen von: einer bunten Spirale, einem Regenbogen aus konzentrischen Kreisen und einem abstrakten Muster mit wechselnder Linienstärke. Fügen Sie die Möglichkeit hinzu, das Ergebnis über JavaScript in eine PNG-Datei zu speichern.
Hinweise: Fügen Sie der Turtle-Klasse Slots setColor() und setWidth() hinzu, die QPen über QPainter::setPen() ändern. Erstellen Sie zum Speichern der Datei einen Slot save(filename) mit QPixmap::save(). Verwenden Sie in Skripten Schleifen mit sich ändernden Farb- und Stärkeparametern. Der Klassenname in JavaScript sollte über setProperty() registriert werden.
Schwieriges Level

Interaktiver Editor mit JavaScript-Plugins
Erstellen Sie einen Texteditor mit JavaScript-Plugin-Unterstützung. Der Editor sollte .js-Dateien aus dem plugins-Ordner laden und ihnen eine API zur Arbeit mit Text bereitstellen: getText(), setText(), insertText(), getSelection(), replaceSelection(). Implementieren Sie drei Plugins: (1) Textstatistik-Berechnung (Wörter, Zeichen, Sätze), (2) automatische Code-Formatierung (Einrückungen hinzufügen), (3) Suchen und Ersetzen mit regulären Ausdrücken. Plugins sollten eigene Schaltflächen im Interface haben und beim Start dynamisch registriert werden.
Hinweise: Erstellen Sie eine TextEditorAPI-Klasse mit Slots zur Arbeit mit QTextEdit-Text. Scannen Sie den plugins-Ordner über QDir::entryList(). Jedes Plugin sollte ein Objekt mit einer execute()-Methode und name-, description-Properties zurückgeben. Verwenden Sie QJSValue::property() zum Extrahieren von Plugin-Informationen. Erstellen Sie dynamisch Schaltflächen für jedes Plugin und verbinden Sie deren clicked mit dem Aufruf der entsprechenden Funktion über evaluate(). Behandeln Sie Plugin-Ladefehler.

💬 Treten Sie der Diskussion bei!

Haben Sie die Schildkröten-Grafik zum Laufen gebracht? Welche Muster haben Sie beim Experimentieren mit Winkeln erstellt?

Teilen Sie Ihre JavaScript-Plugins für Qt, diskutieren Sie die Besonderheiten der QJSEngine-Integration in echten Projekten oder stellen Sie Fragen dazu, wann Skripte anstelle von C++ verwendet werden sollten!

Leave a Reply

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