Signal- und Handler-Ereignissystem
Anwendungs- und Benutzerschnittstellenkomponenten müssen miteinander kommunizieren. So muss beispielsweise eine Schaltfläche wissen, dass der Benutzer sie angeklickt hat. Die Schaltfläche kann ihre Farbe ändern, um ihren Zustand anzuzeigen oder eine bestimmte Logik auszuführen. Außerdem muss die Anwendung wissen, ob der Benutzer die Schaltfläche anklickt. Möglicherweise muss die Anwendung dieses Klickereignis an andere Anwendungen weiterleiten.
QML hat einen Signal- und Handler-Mechanismus, bei dem das Signal das Ereignis ist und auf das Signal durch einen Signal-Handler reagiert wird. Wenn ein Signal ausgelöst wird, wird der entsprechende Signal-Handler aufgerufen. Durch das Einfügen von Logik, wie z. B. einem Skript oder anderen Operationen, in den Handler kann die Komponente auf das Ereignis reagieren.
Empfangen von Signalen mit Signalhandlern
Um eine Benachrichtigung zu erhalten, wenn ein bestimmtes Signal für ein bestimmtes Objekt ausgegeben wird, sollte in der Objektdefinition ein Signal-Handler mit dem Namen on<Signal> deklariert werden, wobei <Signal> der Name des Signals ist, wobei der erste Buchstabe groß geschrieben wird. Der Signal-Handler sollte den JavaScript-Code enthalten, der ausgeführt werden soll, wenn der Signal-Handler aufgerufen wird.
Zum Beispiel hat der Typ Button aus dem Qt Quick Controls Modul ein Signal clicked
, das immer dann ausgegeben wird, wenn die Schaltfläche angeklickt wird. In diesem Fall sollte der Signalhandler für den Empfang dieses Signals onClicked
sein. Im folgenden Beispiel wird bei jedem Anklicken der Schaltfläche der Handler onClicked
aufgerufen, der dem übergeordneten Rectangle eine zufällige Farbe zuweist:
import QtQuick import QtQuick.Controls Rectangle { id: rect width: 250; height: 250 Button { anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter text: "Change color!" onClicked: { rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1); } } }
Hinweis: Auch wenn Signal-Handler ein wenig wie JavaScript-Funktionen aussehen, sollten Sie sie nicht direkt aufrufen. Wenn Sie Code zwischen Signalhandlern und anderen Funktionen austauschen müssen, wandeln Sie ihn in eine separate Funktion um. Andernfalls sollten Sie das Signal immer ausgeben, wenn Sie möchten, dass der Signal-Handler aufgerufen wird. Für ein und dasselbe Signal kann es mehrere Handler in verschiedenen Bereichen geben.
Handler für Eigenschaftsänderungssignale
Ein Signal wird automatisch ausgesendet, wenn sich der Wert einer QML-Eigenschaft ändert. Dieser Signaltyp ist ein Eigenschaftsänderungssignal, und Signalhandler für diese Signale werden in der Form on<Property>Changed geschrieben, wobei <Property> der Name der Eigenschaft ist, wobei der erste Buchstabe groß geschrieben wird.
Zum Beispiel hat der Typ MouseArea eine Eigenschaft pressed. Um eine Benachrichtigung zu erhalten, wenn sich diese Eigenschaft ändert, schreiben Sie einen Signalhandler mit dem Namen onPressedChanged
:
import QtQuick Rectangle { id: rect width: 100; height: 100 TapHandler { onPressedChanged: console.log("taphandler pressed?", pressed) } }
Auch wenn in der Dokumentation TapHandler kein Signalhandler mit dem Namen onPressedChanged
dokumentiert ist, wird das Signal implizit durch die Tatsache bereitgestellt, dass die Eigenschaft pressed
existiert.
Signal-Parameter
Signale können Parameter haben. Um auf diese zuzugreifen, sollten Sie dem Handler eine Funktion zuweisen. Sowohl Pfeilfunktionen als auch anonyme Funktionen funktionieren.
Für die folgenden Beispiele betrachten wir eine Status-Komponente mit einem errorOccurred-Signal (siehe Hinzufügen von Signalen zu benutzerdefinierten QML-Typen für weitere Informationen darüber, wie Signale zu QML-Komponenten hinzugefügt werden können).
// Status.qml import QtQuick Item { id: myitem signal errorOccurred(message: string, line: int, column: int) }
Status { onErrorOccurred: (mgs, line, col) => console.log(`${line}:${col}: ${msg}`) }
Hinweis: Die Namen der formalen Parameter in der Funktion müssen nicht mit denen im Signal übereinstimmen.
Wenn Sie nicht alle Parameter verarbeiten müssen, können Sie die nachgestellten Parameter weglassen:
Status { onErrorOccurred: message => console.log(message) }
Es ist nicht möglich, führende Parameter, an denen Sie interessiert sind, wegzulassen, aber Sie können einen Platzhalternamen verwenden, um den Lesern anzuzeigen, dass sie nicht wichtig sind:
Status { onErrorOccurred: (_, _, col) => console.log(`Error happened at column ${col}`) }
Hinweis: Anstelle einer Funktion kann auch ein einfacher Codeblock verwendet werden, wovon jedoch abgeraten wird. In diesem Fall werden alle Signalparameter in den Bereich des Blocks injiziert. Dies kann jedoch die Lesbarkeit des Codes erschweren, da es unklar ist, woher die Parameter kommen, und führt zu langsameren Suchvorgängen in der QML-Engine. Die Injektion von Parametern auf diese Weise ist veraltet und führt zu Laufzeitwarnungen, wenn der Parameter tatsächlich verwendet wird.
Verwendung des Typs Connections
In einigen Fällen kann es wünschenswert sein, auf ein Signal außerhalb des Objekts zuzugreifen, das es aussendet. Für diese Zwecke bietet das Modul QtQuick
den Typ Connections für die Verbindung zu Signalen beliebiger Objekte. Ein Connections Objekt kann jedes Signal von seinem angegebenen target empfangen.
Zum Beispiel hätte der onClicked
Handler im vorherigen Beispiel stattdessen von der Wurzel Rectangle empfangen werden können, indem man den onClicked
Handler in einem Connections Objekt platziert, dessen target auf button
gesetzt ist:
import QtQuick import QtQuick.Controls Rectangle { id: rect width: 250; height: 250 Button { id: button anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter text: "Change color!" } Connections { target: button function onClicked() { rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1); } } }
Angehängte Signal-Handler
Ein angehängter Signal-Handler empfängt ein Signal von einem anhängenden Typ und nicht von dem Objekt, in dem der Handler deklariert ist.
Zum Beispiel ist Component.onCompleted ein angehängter Signal-Handler. Er wird häufig verwendet, um JavaScript-Code auszuführen, wenn sein Erstellungsprozess abgeschlossen ist. Hier ist ein Beispiel:
import QtQuick Rectangle { width: 200; height: 200 color: Qt.rgba(Qt.random(), Qt.random(), Qt.random(), 1) Component.onCompleted: { console.log("The rectangle's color is", color) } }
Der onCompleted
Handler reagiert nicht auf ein completed
Signal vom Typ Rectangle. Stattdessen wurde von der QML-Engine automatisch ein Objekt des Typs Component
mit einem completed
-Signal an das Objekt Rectangle angehängt. Die Engine gibt dieses Signal aus, wenn das Rectangle-Objekt erstellt wird, und löst damit den Component.onCompleted
signal handler aus.
Durch angehängte Signalhandler können Objekte über bestimmte Signale benachrichtigt werden, die für jedes einzelne Objekt von Bedeutung sind. Gäbe es z. B. keinen Component.onCompleted
attached signal handler, könnte ein Objekt diese Benachrichtigung nicht erhalten, ohne sich für ein spezielles Signal von einem speziellen Objekt zu registrieren. Der Mechanismus der angehängten Signalhandler ermöglicht es Objekten, bestimmte Signale ohne zusätzlichen Code zu empfangen.
Weitere Informationen über angehängte Signalhandler finden Sie unter Angehängte Eigenschaften und angehängte Signalhandler.
Hinzufügen von Signalen zu benutzerdefinierten QML-Typen
Signale können zu benutzerdefinierten QML-Typen mit dem Schlüsselwort signal
hinzugefügt werden.
Die Syntax für die Definition eines neuen Signals lautet:
signal <name>[([<type> <parameter name>[, ...]])]
Ein Signal wird durch den Aufruf des Signals als Methode ausgelöst.
Der folgende Code ist beispielsweise in einer Datei namens SquareButton.qml
definiert. Das Stammobjekt Rectangle hat ein Signal activated
, das immer dann ausgegeben wird, wenn das untergeordnete Objekt TapHandler tapped
ist. In diesem speziellen Beispiel wird das aktivierte Signal mit den x- und y-Koordinaten des Mausklicks ausgegeben:
// SquareButton.qml import QtQuick Rectangle { id: root signal activated(real xPosition, real yPosition) property point mouseXY property int side: 100 width: side; height: side TapHandler { id: handler onTapped: root.activated(root.mouseXY.x, root.mouseXY.y) onPressedChanged: root.mouseXY = handler.point.position } }
Nun können beliebige Objekte des SquareButton
über einen onActivated
Signalhandler eine Verbindung zu dem activated
Signal herstellen:
// myapplication.qml SquareButton { onActivated: (xPosition, yPosition) => console.log(`Activated at {xPosition}, ${yPosition}`) }
Siehe Signalattribute für weitere Details zum Schreiben von Signalen für benutzerdefinierte QML-Typen.
Verbinden von Signalen mit Methoden und Signalen
Signalobjekte haben eine connect()
Methode um ein Signal entweder mit einer Methode oder einem anderen Signal zu verbinden. Wenn ein Signal mit einer Methode verbunden ist, wird die Methode automatisch aufgerufen, sobald das Signal ausgesendet wird. Dieser Mechanismus ermöglicht es, dass ein Signal von einer Methode anstelle eines Signalhandlers empfangen werden kann.
Im Folgenden wird das Signal messageReceived
mit drei Methoden verbunden, wobei die Methode connect()
verwendet wird:
import QtQuick Rectangle { id: relay signal messageReceived(string person, string notice) Component.onCompleted: { relay.messageReceived.connect(sendToPost) relay.messageReceived.connect(sendToTelegraph) relay.messageReceived.connect(sendToEmail) relay.messageReceived("Tom", "Happy Birthday") } function sendToPost(person: string, notice: string) { console.log(`Sending to post: ${person}, ${notice}`) } function sendToTelegraph(person: string, notice: string) { console.log(`Sending to telegraph: ${person}, ${notice}`) } function sendToEmail(person: string, notice: string) { console.log(`Sending to email: ${person}, ${notice}`) } }
In vielen Fällen ist es ausreichend, Signale über Signalhandler zu empfangen, anstatt die connect()-Funktion zu verwenden. Mit der Methode connect
kann ein Signal jedoch, wie oben gezeigt, von mehreren Methoden empfangen werden, was mit Signal-Handlern nicht möglich wäre, da diese eindeutig benannt werden müssen. Außerdem ist die Methode connect
nützlich, wenn Signale mit dynamisch erstellten Objekten verbunden werden.
Es gibt eine entsprechende disconnect()
-Methode zum Entfernen von verbundenen Signalen:
Rectangle { id: relay //... function removeTelegraphSignal() { relay.messageReceived.disconnect(sendToTelegraph) } }
Signal zu Signal verbinden
Durch die Verbindung von Signalen mit anderen Signalen können mit der Methode connect()
verschiedene Signalketten gebildet werden.
import QtQuick Rectangle { id: forwarder width: 100; height: 100 signal send() onSend: console.log("Send clicked") TapHandler { id: mousearea anchors.fill: parent onTapped: console.log("Mouse clicked") } Component.onCompleted: { mousearea.tapped.connect(send) } }
Immer wenn das Signal tapped
von TapHandler ausgegeben wird, wird automatisch auch das Signal send
ausgegeben.
output: MouseArea clicked Send clicked
Hinweis: Verbindungen zu Funktionsobjekten bleiben so lange bestehen, wie der Absender des Signals aktiv ist. Dieses Verhalten ist analog zu der 3-Argument-Version von QObject::connect() in C++.
Window { visible: true width: 400 height: 400 Item { id: item property color globalColor: "red" Button { text: "Change global color" onPressed: { item.globalColor = item.globalColor === Qt.color("red") ? "green" : "red" } } Button { x: 150 text: "Clear rectangles" onPressed: repeater.model = 0 } Repeater { id: repeater model: 5 Rectangle { id: rect color: "red" width: 50 height: 50 x: (width + 2) * index + 2 y: 100 Component.onCompleted: { if (index % 2 === 0) { item.globalColorChanged.connect(() => { color = item.globalColor }) } } } } } }
Im obigen Beispiel ist das Ziel, die Farbe jedes geraden Rechtecks so zu ändern, dass sie einer globalen Farbe folgt. Um dies zu erreichen, wird für jedes gerade Rechteck eine Verbindung zwischen dem Signal globalColorChanged und einer Funktion zum Setzen der Farbe des Rechtecks hergestellt. Dies funktioniert wie erwartet, solange die Rechtecke aktiv sind. Sobald jedoch die Löschtaste gedrückt wird, sind die Rechtecke verschwunden, aber die Funktion, die das Signal verarbeitet, wird immer noch jedes Mal aufgerufen, wenn das Signal ausgegeben wird. Dies lässt sich an den Fehlermeldungen erkennen, die von der Funktion ausgegeben werden, die versucht, im Hintergrund zu laufen, wenn sie die globale Farbe ändert.
In der derzeitigen Konfiguration würden die Verbindungen erst zerstört, wenn das Element, das globalColor enthält, zerstört wird. Um zu verhindern, dass die Verbindungen weiter bestehen bleiben, können sie explizit getrennt werden, wenn die Rechtecke zerstört werden.
© 2025 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.