Sur cette page

Système d’événements : signaux et gestionnaires

Les composants de l'application et de l'interface utilisateur doivent communiquer entre eux. Par exemple, un bouton doit savoir que l'utilisateur a cliqué dessus. Le bouton peut changer de couleur pour indiquer son état ou exécuter une logique. De même, l'application doit savoir si l'utilisateur clique sur le bouton. L'application peut avoir besoin de relayer cet événement de clic à d'autres applications.

QML dispose d’un mécanisme de signaux et de gestionnaires, dans lequel le signal correspond à l’événement et la réponse à ce signal s’effectue via un gestionnaire de signal. Lorsqu’un signal est émis, le gestionnaire de signal correspondant est invoqué. L’intégration d’une logique, telle qu’un script ou d’autres opérations, dans le gestionnaire permet au composant de réagir à l’événement.

Réception de signaux à l'aide de gestionnaires de signaux

Pour recevoir une notification lorsqu’un signal particulier est émis pour un objet donné, la définition de l’objet doit déclarer un gestionnaire de signal nommé on<Signal>, où <Signal> est le nom du signal, dont la première lettre est en majuscule. Le gestionnaire de signal doit contenir le code JavaScript à exécuter lorsqu’il est appelé.

Par exemple, le type ` Button ` du Qt Quick Controls dispose d’un signal « clicked », qui est émis chaque fois que l’on clique sur le bouton. Dans ce cas, le gestionnaire de signal permettant de recevoir ce signal doit être « onClicked ». Dans l’exemple ci-dessous, chaque fois que l’on clique sur le bouton, le gestionnaire « onClicked » est appelé, appliquant une couleur aléatoire à l’objet parent « Rectangle » :

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);
        }
    }
}

Remarque : même si les gestionnaires de signaux ressemblent un peu à des fonctions JavaScript, vous ne devez pas les appeler directement. Si vous avez besoin de partager du code entre des gestionnaires de signaux et d’autres fonctionnalités, refactorisez-le en une fonction distincte. Sinon, émettez toujours le signal si vous souhaitez que le gestionnaire de signal soit appelé. Il peut y avoir plusieurs gestionnaires, dans des portées différentes, pour un même signal.

Gestionnaires de signaux de modification de propriété

Un signal est automatiquement émis lorsque la valeur d’une propriété QML change. Ce type de signal est un signal de changement de propriété et les gestionnaires de signaux pour ces signaux s’écrivent sous la forme on<Propriété>Changed, où <Propriété> est le nom de la propriété, dont la première lettre est en majuscule.

Par exemple, le type « MouseArea » dispose d’une propriété « pressed ». Pour recevoir une notification chaque fois que cette propriété change, écrivez un gestionnaire de signal nommé « onPressedChanged » :

import QtQuick

Rectangle {
    id: rect
    width: 100; height: 100

    TapHandler {
        onPressedChanged: console.log("taphandler pressed?", pressed)
    }
}

Même si la documentation d’ TapHandler ne mentionne pas de gestionnaire de signal nommé onPressedChanged, ce signal est implicitement fourni par le fait que la propriété pressed existe.

Paramètres du signal

Les signaux peuvent avoir des paramètres. Pour y accéder, vous devez attribuer une fonction au gestionnaire. Les fonctions fléchées et les fonctions anonymes fonctionnent toutes les deux.

Pour les exemples suivants, prenons le cas d’un composant Status doté d’un signal errorOccurred (voir Ajouter des signaux à des types QML personnalisés pour plus d’informations sur la manière d’ajouter des signaux à des composants QML).

// 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}`)
}

Remarque : les noms des paramètres formels de la fonction ne doivent pas nécessairement correspondre à ceux du signal.

Si vous n'avez pas besoin de traiter tous les paramètres, vous pouvez omettre ceux qui se trouvent à la fin :

Status {
    onErrorOccurred: message => console.log(message)
}

Il n'est pas possible d'omettre les paramètres de début qui vous intéressent ; vous pouvez toutefois utiliser un nom de remplacement pour indiquer aux lecteurs qu'ils ne sont pas importants :

Status {
    onErrorOccurred: (_, _, col) => console.log(`Error happened at column ${col}`)
}

Remarque : au lieu d’utiliser une fonction, il est possible, bien que déconseillé, d’utiliser un simple bloc de code. Dans ce cas, tous les paramètres du signal sont injectés dans la portée du bloc. Cependant, cela peut rendre le code difficile à lire, car l'origine des paramètres n'est pas claire, et cela ralentit les recherches dans le moteur QML. L'injection de paramètres de cette manière est dépréciée et provoquera des avertissements lors de l'exécution si le paramètre est effectivement utilisé.

Utilisation de l’objet spécial « arguments »

En JavaScript, vous pouvez faire référence à l’objet spécial « arguments » qui, lorsqu’il est disponible, permet d’accéder aux valeurs des arguments passés à une fonction non fléchée sous la forme d’un objet de type tableau.

Il est généralement disponible dans le corps d'une fonction ou d'un bloc de code attribué à un gestionnaire d'événement.

Lorsqu’un bloc de code ou une fonction anonyme est attribué au gestionnaire de signal, l’objet spécial ` arguments ` fournira les arguments qui ont été transmis par le signal.

Par exemple, les deux instructions suivantes afficheront « [object Arguments] world undefined » :

import QtQml

QtObject {
    id: root

    signal hello(message: string)

    onHello: { console.log(arguments, arguments[0], arguments[1]) }

    Component.onCompleted: root.hello("world")
}
import QtQml

QtObject {
    id: root

    signal hello(message: string)

    onHello: function () { console.log(arguments, arguments[0], arguments[1]) }

    Component.onCompleted: root.hello("world")
}

Le comportement sera différent lorsqu'une fonction flèche est attribuée au gestionnaire de signal. Dans ce cas, il sera toujours possible d'accéder à l'objet spécial ` arguments `, mais il s'agira d'un objet de type tableau vide.

Par exemple, le code suivant affichera « [object Arguments] undefined undefined » :

import QtQml

QtObject {
    id: root

    signal hello(message: string)

    onHello: () => { console.log(arguments, arguments[0], arguments[1]) }

    Component.onCompleted: root.hello("world")
}

Cette différence de comportement est due à la manière dont l’objet spécial ` arguments ` interagit avec les fonctions flèches, mais elle est cohérente avec le comportement général des liaisons.

Selon la spécification, une fonction flèche ne possède pas son propre objet spécial « arguments ». Comme une fonction flèche emprunte toujours à son contexte englobant, elle peut emprunter l’objet spécial « arguments » s’il est disponible.

Une liaison fournit sa propre portée lors de son évaluation. En particulier, la récupération de la fonction flèche sous-jacente s’effectue dans la portée fournie par l’évaluation de la liaison.

Dans la portée de la liaison, aucun argument n’est fourni, de sorte qu’un objet spécial « arguments » vide sera disponible et emprunté par la fonction flèche lors de sa récupération.

Comme une fonction non-flèche fournit bien l’objet spécial ` arguments ` dans sa propre portée, elle peut se référer aux arguments qui ont été fournis à la fonction sous-jacente elle-même, c’est-à-dire les arguments transmis par le signal.

L’utilisation de l’objet spécial ` arguments ` doit généralement être évitée au profit de l’utilisation de paramètres nommés, qui sont plus explicites et fonctionnent de manière cohérente, indépendamment du fait qu’il s’agisse d’une fonction fléchée ou non.

Utilisation du type Connections

Dans certains cas, il peut être souhaitable d’accéder à un signal en dehors de l’objet qui l’émet. À cette fin, le module QtQuick fournit le type Connections permettant de se connecter à des signaux d’objets arbitraires. Un objet Connections peut recevoir n’importe quel signal provenant de son target spécifié.

Par exemple, le gestionnaire ` onClicked ` de l’exemple précédent aurait pu être reçu par l’` Rectangle ` racine à la place, en plaçant le gestionnaire ` onClicked ` dans un objet ` Connections ` dont la propriété ` target ` est définie sur ` button` :

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);
        }
    }
}

Gestionnaires de signaux associés

Un gestionnaire de signal attaché reçoit un signal provenant d’un type d’attachement plutôt que de l’objet au sein duquel le gestionnaire est déclaré.

Par exemple, ` Component.onCompleted ` est un gestionnaire de signal attaché. Il est souvent utilisé pour exécuter du code JavaScript une fois son processus de création terminé. Voici un exemple :

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)
    }
}

Le gestionnaire onCompleted ne répond pas à un signal completed provenant du type Rectangle. À la place, un objet du type attachant Component, doté d’un signal completed, a été automatiquement attaché à l’objet Rectangle par le moteur QML. Le moteur émet ce signal lorsque l’objet Rectangle est créé, déclenchant ainsi le gestionnaire de signal Component.onCompleted.

Les gestionnaires de signaux attachés permettent aux objets d’être notifiés de signaux particuliers qui sont significatifs pour chaque objet individuel. S’il n’y avait pas de gestionnaire de signal attaché « Component.onCompleted », par exemple, un objet ne pourrait pas recevoir cette notification sans s’être enregistré pour un signal spécifique provenant d’un objet spécifique. Le mécanisme des gestionnaires de signaux attachés permet aux objets de recevoir des signaux particuliers sans code supplémentaire.

Voir Propriétés associées et gestionnaires de signaux associés pour plus d’informations sur les gestionnaires de signaux associés.

Ajout de signaux à des types QML personnalisés

Les signaux peuvent être ajoutés à des types QML personnalisés à l'aide du mot-clé « signal ».

La syntaxe recommandée pour définir un nouveau signal est la suivante :

signal <name>[([<parameter name> : <type>[, ...]])]

Il existe également une ancienne syntaxe où le type précède le nom :

signal <name>[([<type> <parameter name>[, ...]])]

Vous devriez utiliser la nouvelle syntaxe.

Un signal est émis en appelant le signal comme une méthode.

Par exemple, le code ci-dessous est défini dans un fichier nommé SquareButton.qml. L'objet racine Rectangle dispose d'un signal activated, qui est émis chaque fois que l'enfant TapHandler est tapped. Dans cet exemple particulier, le signal activé est émis avec les coordonnées x et y du clic de souris :

// SquareButton.qml
import QtQuick

Rectangle {
    id: root

    signal activated(xPosition: real, yPosition: real)
    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
    }
}

Désormais, tous les objets de l’ SquareButton peuvent se connecter au signal activated à l’aide d’un gestionnaire de signal onActivated:

// myapplication.qml
SquareButton {
    onActivated: (xPosition, yPosition) => console.log(`Activated at {xPosition}, ${yPosition}`)
}

Consultez la section « Attributs des signaux » pour plus de détails sur la création de signaux pour les types QML personnalisés.

Connexion de signaux à des méthodes et à d'autres signaux

Les objets « signal » disposent d’une méthode « connect() » permettant de connecter un signal soit à une méthode, soit à un autre signal. Lorsqu’un signal est connecté à une méthode, celle-ci est automatiquement appelée chaque fois que le signal est émis. Ce mécanisme permet à un signal d’être reçu par une méthode plutôt que par un gestionnaire de signal.

Ci-dessous, le signal « messageReceived » est connecté à trois méthodes à l'aide de la méthode « connect() » :

import QtQuick

Rectangle {
    id: relay

    signal messageReceived(person: string, notice: string)

    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}`)
    }
}

Dans de nombreux cas, il suffit de recevoir les signaux via des gestionnaires de signaux plutôt que d’utiliser la fonction `connect()`. Cependant, l’utilisation de la méthode ` connect ` permet à un signal d’être reçu par plusieurs méthodes, comme illustré précédemment, ce qui serait impossible avec des gestionnaires de signaux, car ceux-ci doivent porter un nom unique. De plus, la méthode ` connect ` est utile pour connecter des signaux à des objets créés dynamiquement.

Il existe une méthode disconnect() correspondante pour supprimer les signaux connectés :

Rectangle {
    id: relay
    //...

    function removeTelegraphSignal() {
        relay.messageReceived.disconnect(sendToTelegraph)
    }
}

Connexion de signal à signal

En connectant des signaux à d'autres signaux, la méthode « connect() » permet de former différentes chaînes de signaux.

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)
    }
}

Chaque fois que le signal « tapped » de l’ TapHandler est émis, le signal « send » est automatiquement émis à son tour.

output:
    MouseArea clicked
    Send clicked

Remarque : les connexions aux objets de fonction resteront actives tant que l’émetteur du signal sera actif. Ce comportement est analogue à la version à trois arguments de la fonction QObject::connect() en 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
                        })
                    }
                }
            }
        }
    }
}

Dans l’exemple artificiel ci-dessus, l’objectif est d’inverser la couleur de chaque rectangle pair pour qu’il suive une couleur globale. Pour ce faire, pour chaque rectangle pair, une connexion est établie entre le signal `globalColorChanged` et une fonction permettant de définir la couleur du rectangle. Cela fonctionne comme prévu tant que les rectangles sont actifs. Cependant, une fois que l’on appuie sur le bouton « Effacer », les rectangles disparaissent mais la fonction gérant le signal continue d’être appelée à chaque fois que celui-ci est émis. Cela est visible grâce aux messages d’erreur générés par la fonction qui tente de s’exécuter en arrière-plan lors du changement de la couleur globale.

Dans la configuration actuelle, les connexions ne seraient rompues qu’une fois que l’élément contenant `globalColor` serait détruit. Pour éviter que les connexions ne persistent, elles peuvent être explicitement déconnectées lors de la destruction des rectangles.

© 2026 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.