Les évènements



Dans le cours d'introduction à la programmation, nous avons vu qu'un évènement est le résultat d'une action de l'utilisateur sur l'interface graphique d'un programme. Toute action sur le clavier ou la souris provoque une interruption, qui est d'abord capturée par le système d'exploitation. Si le curseur de la souris est à ce moment là situé au dessus de la fenêtre d'une application, le système va alors lui retransmettre cette interruption.

Un évènement sera alors généré au sein de l'application.

Jusqu'ici, le seul type d'évènement que nous avons considéré est le clic sur un bouton. Il existe en réalité de nombreux autres types d'évènements et de plus ils peuvent être associés à différents types de composant.

Dans cette partie du cours nous allons voir de nouveaux types d'évènements et comment leur associer un gestionnaire d'évènement ou autrement dit, une procédure évènementielle.

Utilisation de l'onglet évènement

Pour connaitre les évènements associer à un composant

Dans Lazarus, tout composant graphique peut intercepter des évènements de différents types. Pour les connaitre, il suffit de cliquer sur le composant, puis sur l'onglet Evenement de l'inspecteur d'objet.

Voici, par exemple l'onglet évènement d'un bouton, d'une zone de texte, d'une étiquette ou d'un formulaire.

Chaque ligne de l'onglet Evenement correspond à un attribut de la classe représentant le composant. Les noms des attributs sont dans la colonne de gauche et leurs valeurs respectives dans la colonne de droite.

Tous les attributs commencant par On servent à stocker un pointeur vers un gestionnaire d'évènement. Le nom de l'évènement en question est défini par la chaine de caractère qui suit On.

Reprenons par exemple l'onglet Evenement du bouton Additionner. OnClick représente ici un attribut de la classe TButton (classe représentant les boutons). La valeur de cet attribut est BoutonAdditionnerClick. Il pointe donc vers l'adresse en mémoire de la procédure évènementielle BoutonAdditionnerClick.

Notez également que Lazarus génère un nom par défaut pour le gestionnaire d'évènement. Il est formé du nom du composant, suivi du nom de l'évènement.

En comparant les exemples d'onglets Evènement précédents, on constate que certains évènements peuvent se retrouver dans plusieurs composants. C'est le cas par exemple de l'évènement OnClick, que l'on retrouve aussi bien dans l'onglet évènement d'un bouton que dans celui d'une etiquette, ou d'une zone de texte ou d'un formulaire.

D'autres, par contre sont spécifiques à certains composants. L'évènement OnEditingDone par exemple existe pour les zones de texte, mais pas pour les boutons, ni les formulaires, ni les etiquettes.

Pour associer un gestionnaire d'évènement à un composant

Chaque composant possède un évènement par défaut. Par exemple Click pour un bouton ou une étiquette , Change pour une zone de texte et Create pour un formulaire.

Lorsque vous double-cliquez sur un composant, Lazarus considère que vous voulez écrire le gestionnaire d'évènement pour l'évènement par défaut de ce composant. Il va donc automatiquement générer une procédure évènementielle de la forme suivante dans le code de l'application:

procedure TForm1.XY(Sender: TObject);
begin
end; 

X est le nom du composant et Y le nom de l'évènement par défaut de ce composant. D'autre part, cette procédure évènementielle sera déclarée en tant que méthode de la classe TForm1.

Par exemple, avec l'interface graphique suivante:

Formulaire-ProjetAddition.jpg, 26kB

un double-clic sur le bouton Additionner (dont le nom interne est BoutonAdditionner), génère automatiquement la procédure évènementielle suivante:

procedure TForm1.BoutonAdditionnerClick(Sender: TObject);
begin

end; 

car l'évènement Click est l'évènement par défaut des bouton.

Lorsque l'on affiche l'onglet Evènement de ce bouton, on constate que la procédure évènementielle est bien enregistrée dans l'attribut OnClick de cet objet:

BoutonAdditonnerClick.jpg, 39kB

Comment fait alors pour écrire un gestionnaire d'évènement d'un composant lorsque cet évènement n'est pas l'évènement par défaut de ce composant ?

C'est ici qu'intervient l'onglet évènement. Supposons par exemple que nous souhaitons gèrer l'évènement EditingDone d'une zone de texte. Comme il ne s'agit pas de l'évènement par défaut, il faut ouvrir l'onglet évènement du composant et cliquer sur les ... de l'attibut OnEditingDone, comme dans l'exemple suivant: suivant:

OngletEvnt-TroisPetitsPoints.jpg, 65kB

et Lazarus génèrera alors le code initial du gestionnaire d'évènement dans le code source (la zone de texte se nomme ZoneTexteX):

procedure TForm1.ZoneTexteXEditingDone(Sender: TObject);
begin

end; 

et constate que cette procédure évènementielle est enregistré dans l'attribut OnEditingDone:

OngletEvnt-TroisPetitsPointsApresClick.jpg, 63kB

Quelques évènements utiles

Dans les applications courantes, il est rare de devoir gèrer d'autres évènements que le clic. Les suivants pourront toute fois vous être utiles dans de nombreux cas:

Exemple

L'exemple présenté ici se trouve sous le répertoire Exemple-ProgObjet1/Evenement. Il s'agit d'une nouvelle version du programme d'addition fonctionnant sans bouton. Cet exemple illustre l'utilisation des différents types d'évènements dont nous avons parlé précédemment. Voici, le formulaire de cet application:

Addition-Sans-Bouton.jpg, 20kB
Utilisation de Editing Done

La somme des deux nombres est effectuée dès que l'utilisateur appuie sur la touche Entrée dans une des deux zones de texte etiquetée X ou Y (ZoneTexteX et ZoneTexteY respectivement). Ceci est réalisé grâce à la gestion de l'évènement EditingDone.

Voici le code du gestionnaire de l'évènement EditingDone pour ZoneTexteX:

procedure TForm1.ZoneTexteXEditingDone(Sender: TObject);
begin
 Additionner ();
end;

et celui du gestionnaire de l'évènement EditingDone pour ZoneTexteY:

procedure TForm1.ZoneTexteYEditingDone(Sender: TObject);
begin
  Additionner ();
end; 

les deux procédures appellent la procédure Additionner qui lit les deux nombres à afficher puis affiche leur somme dans la zone de texte étiquetée X+Y.

Clic sur une étiquette

Un clic sur les étiquettes X ou Y (respectivement Etiquette_X et Etiquette_Y) efface les zones de texte associée (ZoneTexteX et ZoneTexteY respectivement).

Voici le code du gestionnaire de l'évènement Click pour Etiquette_X:

procedure TForm1.Etiquette_XClick(Sender: TObject);
begin
  Effacer(ZoneTexteX);
end; 

et celui du gestionnaire de l'évènement Click pour Etiquette_Y:

procedure TForm1.Etiquette_YClick(Sender: TObject);
begin
  Effacer(ZoneTexteY);
end; 
Utilisation de Resize

Si vous élargissez la fenêtre, vous constaterez que la dimension des zones de texte augmente. On obtiendra par exemple ceci:

Addition-Elargie.jpg, 20kB

Nous nous sommes en fait arrangé pour que la différence entre la largeur de la fenêtre et celle des zones de texte reste constante. Pour cela, la différence entre les deux largeurs est mémorisé dans une variable globale dès le démarrage dans l'application. Nous avons donc placé cette instruction dans FormCreate:

procedure TForm1.FormCreate(Sender: TObject);
begin
  DifferenceLargeur := Form1.width - ZoneTexteX.Width;
end;  

Un redimensionnement de la fenêtre génère un évènement Resize associé au formulaire (Form1). Pour maintenir une différence de largeur constante, nous avons écrit le gestionnaire d'évènement Resize de Form1. Le voici:

procedure TForm1.FormResize(Sender: TObject);
var NouvelleLargeur : integer;
begin
  NouvelleLargeur := Form1.width - DifferenceLargeur;
  ZoneTexteX.width := NouvelleLargeur;
  ZoneTexteY.width := NouvelleLargeur;
  ZoneTexteSomme.width :=  NouvelleLargeur;
end;
Utilisation de DblClick, CloseQuery

Un double clic sur le formulaire provoque l'apparition de la boite de dialogue suivante:

Addition-DblClick.jpg, 14kB

Si l'utilisateur clic sur le bouton 'Non', l'application reste ouverte. S'il clique sur 'Oui', elle se termine.

Cette boite de dialogue est affichée par la fonction Confirmation. Elle affiche une boite de dialogue demandant à l'utilisateur de confirmer son choix.

Si l'utilisateur ne clique pas le bouton par défaut (ici Non), la fonction retourne True.

Logiquement si double clic sur le formulaire provoque l'affichage de la boite de dialogue, c'est nécessairement par l'intermédiaire du gestionnaire de l'évènement DblClick de Form1. Le voici:

procedure TForm1.FormDblClick(Sender: TObject);
begin
  Form1.Close();
end; 

Oh surprise ! Le gestionnaire n'appelle pas la fonction Confirmation. Comment le double-clic peut il alors faire apparaitre la boite de dialogue ?

Logiquement Form1.Close devrait fermer immédiatement la fenêtre.

L'explication de ce mystère est la suivante. La méthode Close génère l'évènement CLoseQuery associé au formulaire Form1 et c'est donc dans le gestionnaire de cet évènement que se trouve l'instruction permettant d'afficher la boite de dialogue et de quitter ou de ne pas quitter l'application selon la réponse de l'utilisateur. Voici ce gestionnaire d'évènement:

procedure TForm1.FormCloseQuery
   (Sender: TObject; var CanClose: boolean);
begin
  CanClose := Confirmation ('Mise en garde',
  'Voulez-vous réellement quitter l''application ?',
  'Non','Oui');
end; 

Le paramètre CanClose du gestionnaire détermine si l'application doit être effectivement fermée (CanClose = True dans ce cas).