Developpez.com - Qt
X

Choisissez d'abord la catégorieensuite la rubrique :

Viadeo Twitter Facebook Share on Google+   
Logo Documentation Qt ·  Page d'accueil  ·  Toutes les classes  ·  Toutes les fonctions  ·  Vues d'ensemble  · 

Le système d'événements

Dans Qt, les évènements sont des objets, dérivés depuis la classe abstraite QEvent, qui représentent des choses qui ont eu lieu soit à l'intérieur d'une application, soit comme résultat d'une activité extérieure à l'application.

Introduction

Les évènements peuvent être reçus et pris en charge par n'importe quelle instance d'une sous-classe de QObject. Cela est particulièrement significatif pour les widgets. Ce document décrit la manière dont les évènements sont délivrés et gérés dans le cadre d'une application classique.

Comment sont fournis les évènements

Quand un évènement a lieu, Qt crée un objet d'évènement pour le représenter en construisant une instance de la sous-classe appropriée de QEvent, et la délivre à une instance particulière de QObject (ou à l'une de ses sous-classes) en appelant sa fonction event().

Cette fonction ne manipule pas l'événement lui-même; en se basant sur le type d'événement délivré, elle appelle un gestionnaire d'évènements pour ce type spécifique d'événement, et envoie une réponse basée sur l'acceptation de l'évènement.

Certains évènements, comme QMouseEvent et QKeyEvent, proviennent du système de fenêtrage. D'autres, comme QTimerEvent sont issus de sources différentes ; d'autres encore proviennent de l'application elle-même.

Types d'évènements

La plupart des types d'évènements ont des classes spéciales, en particulier QResizeEvent, QPaintEvent, QMouseEvent, QKeyEvent, et QCloseEvent. Chaque classe dérive de QEvent et y ajoute des fonctions spécifiques à l'évènement. Par exemple, QResizeEvent ajoute les fonctions size() et oldSize() qui permettent aux widgets de découvrir comment leurs dimensions ont été modifiées.

Certaines classes supportent plusieurs types d'évènements. QMouseEvent gère les simples clics, les double clics, les déplacements et les autres opérations apparentées.

Chaque évènement a un type associé, défini dans QEvent::Type, qui peut être utilisé de façon adéquate comme source de « run-time type information » (RTTI) pour déterminer rapidement à partir de quelle sous-classe un objet d'évènement a été construit.

Dans la mesure où les programmes doivent réagir de façons très variées et complexes, les mécanismes d'envoi d'évènements de Qt sont flexibles. La documentation de QCoreApplication::notify() explique de façon concise la totalité du sujet. L'article Qt Quarterly Another Look at Events l'explique de façon plus détaillée. Ici, nous détaillerons suffisamment les choses pour couvrir 95% des applications.

Gestionnaire d'évènements

La méthode classique pour délivrer un évènement est l'appel d'une fonction virtuelle. Par exemple, QPaintEvent est délivré en appelant QWidget::paintEvent(). Cette fonction virtuelle porte la responsabilité de réagir convenablement à cet évènement, normalement en re-peignant le widget. Si vous ne réalisez pas tout le travail nécessaire dans votre implémentation de la fonction virtuelle, il se peut que vous ayez besoin d'appeler l'implémentation de la classe de base.

Par exemple, le code suivant gère les cliques gauches de la souris sur un widget personnalisé de checkbox tout en passant les autres cliques de boutons à la classe QCheckBox de base :

void MyCheckBox::mousePressEvent(QMouseEvent *event)
{
 if (event->button() == Qt::LeftButton) {
	 // traiter le clique du bouton gauche de la souris ici
 } else {
	 // propager les autres boutons à la classe de base
	 QCheckBox::mousePressEvent(event);
 }
}

Si vous voulez remplacer la fonction de la classe de base, vous devez implémenter tout vous-même. Cependant, si vous avez juste besoin d'étendre les fonctionnalités de la classe de base, alors il suffit d'implémenter ce dont vous avez besoin et d'appeler la classe de base pour obtenir le comportement par défaut pour tous les cas que vous ne voulez pas gérer.

Dans certains cas, la fonction spécifique à un évènement n'existe pas, ou peut ne pas être suffisante. L'exemple le plus courant concerne les appuis sur la touche Tab. Normalement, QWidget les intercepte pour modifier le focus du clavier mais certains widgets ont besoin de la touche Tab pour eux-mêmes.

Ces objets peuvent ré-implémenter le manager d'évènement général QObject::event() et traiter l'évènement, soit avant, soit après le traitement habituel. Ils peuvent également remplacer complètement la fonction. Un widget très inhabituel qui interprèterait à la fois Tab et qui aurait un évènement personnalisé spécifique à l'application pourrait contenir la fonction event() suivante :

bool MyWidget::event(QEvent *event)
{
 if (event->type() == QEvent::KeyPress) {
	 QKeyEvent *ke = static_cast<QKeyEvent *>(event);
	 if (ke->key() == Qt::Key_Tab) {
		 // traitement spécial de la touche tab ici
		 return true;
	 }
 } else if (event->type() == MyCustomEventType) {
	 MyCustomEvent *myEvent = static_cast<MyCustomEvent *>(event);
	 // traitement de l'évènement personnalisé ici
	 return true;
 }
 
 return QWidget::event(event);
}

Il faut noter que QWidget::event() est toujours appelée pour les cas non-traités et la valeur de retour indique si l'évènement a été traité avec celle-ci; une valeur à true évite que l'évènement ne soit envoyé à d'autres objets.

Filtres d'évènements

Parfois un objet a besoin de regarder, et peut-être intercepter, les évènements qui sont fournis à un autre objet. En particulier, les boites de dialogue vont classiquement filtrer les frappes du clavier pour certains widgets; par exemple, pour modifier la gestion de la touche Entrée.

La fonction QObject::installEventFilter() active cela en installant un filtre d'évènement, créant ainsi un objet dédié au filtrage, qui recevra les évènements de l'objet cible avec sa fonction QObject::eventFilter(). Un filtre d'évènement va traiter les évènements avant que l'objet destinataire ne le fasse. Cela permet au filtre d'inspecter et/ou de retirer les évènements selon les besoins. Un filtre d'évènement existant peut être retiré en utilisant la fonction QObject::removeEventFilter().

Quand l'implémentation eventFilter() de l'objet filtre est appelée, le filtre peut accepter ou rejeter l'évènement et donc autoriser ou refuser des traitements ultérieurs. Si tous les filtres d'évènement autorisent les traitements ultérieurs d'un évènement (en retournant chacun false), l'évènement est envoyé à l'objet destinataire lui-même. Si l'un d'entre eux arrête le traitement de l'évènement (en retournant true), le destinataire et n'importe quel autre filtre d'évènement ne verront pas du tout l'évènement.

bool FilterObject::eventFilter(QObject *object, QEvent *event)
{
 if (object == target && event->type() == QEvent::KeyPress) {
	 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
	 if (keyEvent->key() == Qt::Key_Tab) {
		 // Traitement spécial de tab
		 return true;
	 } else
		 return false;
 }
 return false;
}

Le code ci-dessus montre une autre façon d'intercepter les évènements d'appui sur la touche Tab envoyés à un widget particulier. Dans ce cas, le filtre gère les évènements pertinents et retourne true pour éviter leur traitement ultérieur. Tous les autres évènements sont ignorés, et le filtre retourne false pour autoriser leur envoi au widget destinataire, via n'importe quels autres filtres d'évènement qui leurs seraient appliqués.

Il est également possible de filtrer tous les évènements pour la totalité de l'application en installant un filtre d'évènement sur la QApplication ou sur l'objet QCoreApplication. De tels filtres globaux d'évènement sont appelés avant les filtres spécifiques à l'objet. C'est très puissant mais cela ralentit la distribution de l'évènement pour chaque évènement de l'application; les autres techniques présentées doivent généralement être utilisées à la place.

L'envoi des évènements

Beaucoup d'applications ont besoin de créer et d'envoyer leurs propres évènements. Vous pouvez envoyer des évènements exactement de la même façon que la boucle évènementielle de Qt. Il faut pour cela construire des objets évènements correspondants et les envoyer avec QCoreApplication::sendEvent() et QCoreApplication::postEvent().

sendEvent() traite l'évènement immédiatement. Quand la fonction se termine, les filtres d'évènement et/ou l'objet lui-même ont déjà traités l'évènement. Pour de nombreuses classes d'évènement, il existe une fonction nommée isAccepted() qui indique si un évènement a été accepté ou rejeté par le dernier gestionnaire appelé.

postEvent() place l'évènement dans une file pour un envoi ultérieur. Lors de son prochain appel, la boucle évènementielle principale de Qt enverra tous les évènements de la file avec quelques optimisations. Par exemple, dans le cas de plusieurs évènements de redimensionnement, ils seront compressés en un seul. Cela s'applique également aux évènements de dessin : QWidget::update() appelle postEvent(), ce qui supprime les scintillements et améliore les performances en évitant les repeintes multiples.

postEvent() est également utilisé durant l'initialisation de l'objet. En effet, l'évènement posté sera généralement envoyé très tôt une fois l'initialisation de l'objet terminée. Lors de l'implémentation d'un widget, il est important de comprendre que les évènements sont délivrés très tôt dans leur durée de vie. Il faut donc être sûr, dans le constructeur, d'initialiser les variables membres très tôt, avant qu'il n'y ait la moindre chance qu'un évènement puisse être reçu par l'objet.

Pour créer des évènements de type personnalisé, vous devrez définir un numéro d'évènement qui soit supérieur à QEvent::User. Vous pouvez également être amené à dériver QEvent pour passer des informations spécifiques concernant votre évènement personnalisé. Voir la documentation de QEvent pour plus de détails.

Remerciements

Merci à <!greattux!> pour la traduction et à <!johnlamericain!> ainsi qu'à <!hornetbzz!> pour leur relecture !

Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. Qt 4.7
Copyright © 2018 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.
Vous avez déniché une erreur, une redirection cassée ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP !
Responsable bénévole de la rubrique Qt : Thibaut Cuvelier -