mardi 18 mars 2014

13 - Les WinForms (ou Windows Forms)

0 commentaires
Ouvrez Visual Studio si ce n'est déjà fait.
Cliquez sur "File" > "New Project".
Sélectionnez "Windows Forms Application" :
404 Image not found
Sélection du modèle de projet.
Image 020.030.10000

Du code a automatiquement été généré, notamment :
  • Program.cs qui est le point d'entrée de votre application.
  • Form1.cs qui est le code de votre fenêtre principale.
  • Form1.Designer.cs qui est le code du designer (à ne pas toucher quand on débute) : c'est le code qui va faire afficher la fenêtre et ses composants.

Program.cs

404 Image not found
Vue d'ensemble du projet fraîchement créé.
Image 020.030.10100
Ça ressemble au code du fichier Program.cs pour une application console, avec tout de même des différences :
  • Il y a [STAThread] juste au-dessus de Main. Ne vous en occupez pas pour l'instant.
  • Il n'y a plus d'argument passé à Main.
  • On utilise maintenant la classe Application et on lui demande de lancer une nouvelle Form1.
Qu'est-ce qu'une Form1 ? :euh:
Pour le savoir, il suffit d'aller jeter un coup d'œil dans Form1.cs. Pour visualiser la partie code, faites unclic-droit et sélectionnez "View Code" :
404 Image not found
Code du fichier Form1.cs.
Image 020.030.10200
Dans le code, vous voyez qu'il y a des nouveaux espaces de noms utilisés : c'est principalement pour l'affichage.
À l'intérieur de notre espace de noms, vous voyez qu'une classe Form1 est déclarée, et qu'elle dérive de la classe Form.
À l'intérieur du constructeur, la méthode InitializeComponent est appelée. Elle est créée dans une autre partie de la classe Form1 située dans Form1.Designer.cs :
404 Image not found
Code du fichier Form1.Designer.cs.
Image 020.030.10500
Vous voyez un bloc nommé "Windows Forms Designer generated code". J'ai laissé ma souris au-dessus pour que vous voyiez ce qu'il contient (on peut aussi l'ouvrir en cliquant sur le plus à gauche).
Pendant qu'on y est, au-dessus de ce bloc vous voyez des lignes bizarres :
1/// <summary>
2/// Clean up any resources being used.
3/// </summary>
4/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
Les lignes qui commencent par trois slashes (barres obliques) sont des lignes de commentaires spéciaux. Ces commentaires sont utilisés pour l'IntelliSense. Vous voyez que les commentaires sont faits avec des balises. Entre deux balises summary vous décrivez brièvement à quoi sert ce qui suit (ce peut être une classe, une méthode, ...) en anglais. S'il s'agit d'une méthode qui prend en entrée des arguments, vous pouvez détailler ce que chacun représente avec des balises param.
Regardez ce qu'affiche l'IntelliSense dans Form1.cs :
404 Image not found
Commentaires affichées par l'IntelliSense.
Image 020.030.10600
On retrouve bien la description de la méthode et du paramètre disposing.
Vous pouvez aller voir les autres balises sur MSDN.

Boîte à outils et contrôles

Je vous l'ai déjà dit, mais laissez-moi vous rafraîchir la mémoire : la boîte à outils (située sur le côté gauche, et accessible aussi depuis "View" > "Toolbox") contient des contrôles.
Les contrôles sont ces objets que vous pouvez déposer dans une fenêtre par un simple glisser-déposer ; par exemple un bouton, une image, ...
La partie Design vous montre l'allure de votre fenêtre. Pour la voir, double-cliquez sur Form1.cs dans l'explorateur de la solution, ou faites un clic-droit dessus et vous pouvez faire "View Designer" pour voir la partie Design (de même que "View Code" pour voir le code).
Placez un bouton dans votre Form1 en faisant un glisser-déposer d'un objet Button dans la partie Design de votre Form1. Vous pouvez l'étirer comme vous voulez.
404 Image not found
Mise en place d'un bouton depuis la boîte à outils.
Image 020.030.20000

Propriétés

Cliquez sur le bouton "Properties" dans l'explorateur de la solution pour afficher les propriétés.
404 Image not found
Un clic sur l'icône "Properties" permet d'afficher la fenêtre de propriétés.
Image 020.030.20100
Vous voyez en bas à droite les propriétés de l'objet sélectionné (ici le bouton) :
404 Image not found
Propriétés de notre bouton.
Image 020.030.20200
Faites débuter le nom de votre bouton par "m_" en changeant sa propriété Name (j'ai personnellement opté pour m_myTestButton).
Essayez par vous-mêmes de modifier des propriétés pour voir ce que ça donne, sachant qu'en bas de la fenêtre de propriétés, vous bénéficiez d'une description de la propriété sélectionnée.

Les gestionnaires d'évènements

But

Ce que l'on veut, c'est effectuer une action lorsqu'un certain évènement est déclenché. Pour cela, il faut déjà savoir quand est déclenché l'évènement dont il est question.
C'est ici qu'entrent en jeu les gestionnaires d'évènements ("event handlers" en anglais). Il servent à indiquer que l'évènement surveillé vient d'être déclenché.

Fonctionnement

Le principe est simple : on attache un gestionnaire d'évènements à un évènement (on dit que l'on s'abonne à l'évènement) en spécifiant une méthode. Cette méthode est appelée lorsque l'évènement est déclenché.
Reprenons notre fameux bouton ; double-cliquez dessus : cela va créer un gestionnaire d'évènements. Voici le code généré (par le double-clic) dans Form1.Designer.cs :
1this.m_myTestButton.Click += new System.EventHandler(this.m_myTestButton_Click);

La propriété Click de mon bouton m_myTestButton est un gestionnaire d'évènements, cela signifie que des méthodes vont être appelées par m_myTestButton à chaque fois que je clique dessus, en l'occurrence la méthode appelée est m_myTestButton_Click.
Du code a aussi été généré automatiquement dans Form1.cs :
1private void m_myTestButton_Click(object sender, EventArgs e)
2{
3
4}

Cela définit une fonction privée, qui ne retourne rien et prend en paramètres deux choses :
  • un objet de type object nommé sender (ici c'est m_myTestButton) ;
  • un objet de type EventArgs nommé e (pour "event") contenant des informations sur l'évènement.
Modifions le texte écrit dans notre bouton ! Un objet de type Button contient une propriété appeléeText qui correspond au texte affiché dans ce bouton. Complétez donc la méthode précédente comme suit :
1private void m_myTestButton_Click(object sender, EventArgs e)
2{
3    m_myTestButton.Text = "Bouton cliqué !";
4}

Appuyez sur F5 pour compiler la solution et lancer le programme en mode debug. Cliquez sur le bouton et là vous verrez que le texte a changé.
Place aux explications concernant cette ligne :
1this.m_myTestButton.Click += new System.EventHandler(this.m_myTestButton_Click);

Si vous laissez la souris sur le mot Click juste derrière this.m_myTestButton., un petit rectangle contenant des descriptions apparaît ; on appelle ça une infobulle (tooltip en anglais). Cette infobulle vous dit que Click est de type System.EventHandler, qu'il est défini dans la classe Control(Button dérive de Control) et on vous dit "Occurs when the control is clicked." ("se produit quand l'utilisateur clique sur le contrôle").
Le += signifie que vous ajoutez une action à effectuer si l'évènement est déclenché. En l'occurrence on ajoute un gestionnaire d'évènements qui appellera la méthode m_myTestButton_Click.
De même, -= signifie que vous enlevez une action à effectuer si l'évènement est déclenché.
Vous pouvez mettre à la suite plusieurs lignes similaires à la précédente ; ici je considère queDoSomethingDoSomethingElse et DoAnotherThing sont des méthodes de la classe Form1 (cf. le "this") :
1this.m_myTestButton.Click += new System.EventHandler(this.DoSomething);
2this.m_myTestButton.Click -= new System.EventHandler(this.DoSomethingElse);
3this.m_myTestButton.Click += new System.EventHandler(this.DoAnotherThing);
Pourquoi avoir utilisé this ici ? :euh:
Nous ne sommes pas obligés. Je les ai simplement mis car ils sont présents dans le code automatiquement généré (dans le fichier Form1.Designer.cs) ; je voulais donc suivre la logique de présentation de code. En revanche, si je devais utiliser les gestionnaires d'évènements pour quelque chose qui n'a rien à voir avec le rendu visuel, je ne les mettrais pas dans Form1.Designer.cs et je n'utiliserais pas this.

Exemples d'évènements

Click est loin d'être le seul évènement de notre bouton. Pour voir tous ses évènements, ouvrez votreForm1 en mode Design et sélectionnez le bouton pour voir ses propriétés dans la fenêtre Properties(assurez-vous que l'éclair de cette fenêtre est sélectionné) :
404 Image not found
Évènements liés au bouton (le bouton avec l'image d'éclair doit être activé).
Image 020.040.10000
Les noms sont intuitifs et comme vous pouvez le constater, il suffit de sélectionner un évènement pour voir sa description en bas. Double-cliquer sur un évènement génère automatiquement le code du gestionnaire d'évènement et de la méthode à appeler. Étudions à présent cette méthode.
Le code de la méthode générée automatiquement est :
1private void m_myTestButton_Click(object sender, EventArgs e)
2{
3    throw new NotImplementedException();
4}

Vous pouvez enlever l'exception, cette ligne est mise par mesure de sécurité pour ne pas oublier de mettre du code.
La méthode prend en entrée deux paramètres, ni plus ni moins. Le premier, de type object, correspond à l'envoyeur ; le second, de type EventArgs, correspond aux arguments de l’évènement.

Envoyeur

Il s'agit d'une référence vers l'objet qui a envoyé l'évènement (ici c'est notre bouton) et qui a été stocké sous le type object. Vous pouvez donc par exemple modifier le texte du bouton comme ceci :
1Button senderButton = (Button)sender;
2senderButton.Text = "Bouton cliqué";

Si vous ne maîtriser pas bien les casts, revoyez le chapitre "Effectuer des conversions". Ici, cette façon de faire est inutile, puisque vous savez qu'il s'agit de m_myTestButton, donc faites plutôt :
1m_myTestButton.Text = "Bouton cliqué";

Dans ce cas précis, sender ne nous sert pas, mais il peut tout de même être utile. Prenons un exemple. Placez un 2e bouton sur votre fenêtre et nommez-le m_myTestButton2.
Pour voir qui est qui, mettez le nom de chaque bouton dans la propriété Text (faisable via la fenêtre Properties, ou alors directement dans le code).
Sélectionnez la même méthode pour l'évènement Click :
404 Image not found
On associe le gestionnaire d'évènements Click du deuxième bouton à la même méthode que le premier.
Image 020.040.20000
Ajoutez un contrôle de type label à votre fenêtre ; vous pouvez trouver ce contrôle dans la boîte à outils, dans Common Controls. Ce contrôle permet d'afficher du texte. Nommez-le m_statusLabel. Mettez la propriété AutoSize à false pour choisir sa taille (sinon il prend la taille du texte qu'il contient). Mettez sa propriété Text à "Aucun bouton cliqué.". Sélectionnez TextAlign et cliquez sur le rectangle du milieu. TextAlign doit valoir MiddleCenter à présent (vous l'aurez compris, en place notre texte au beau milieu du label). Modifiez notre méthode comme ceci :
1private void m_myTestButton_Click(object sender, EventArgs e)
2{
3    Button senderButton = (Button)sender;
4    senderButton.Text = "Bouton cliqué";
5    m_statusLabel.Text = senderButton.Name + " vient d'être cliqué.";
6}

Maintenant lancez le programme et cliquez sur les boutons pour admirer le résultat :

Vidéo montrant le programme à l’œuvre avec le gestionnaire d'évènements Click.
Vidéo 020.040.20000

Arguments d'évènement

Ce paramètre contient des informations relatives à l'évènement. Avec le gestionnaire d'évènementsClick, ces informations sont de type EventArgs et ne contiennent rien qui nous intéresse. Nous allons donc tester le gestionnaire d'évènements MouseClick.
La différence est que l'évènement lié à Click est déclenché quand le bouton est cliqué, ce qui peut se faire de diverses manières, notamment en appuyant sur la touche Entrée quand le bouton a le focus (quand il est sélectionné), alors que l'évènement lié à MouseClick n'est déclenché que lorsque le bouton est cliqué avec la souris.
Ouvrez Form1.cs en mode Design et double-cliquez sur "MouseClick" pour faire générer le gestionnaire d'évènements et la méthode associée. Dans le corps de la méthode, tapez : e. et regardez ce que propose l'IntelliSense ; vous voyez les mêmes méthodes qu'avec un objet de type EventArgsainsi que de nouvelles propriétés, dont Location. Modifiez le code comme ceci :
1private void m_myTestButton_MouseClick(object sender, MouseEventArgs e)
2{
3    m_statusLabel.Text = "Bouton n°1 cliqué à la position : " + e.Location + ".";
4}

Et admirez le résultat :

Vidéo montrant le programme à l’œuvre avec le gestionnaire d'évènements MouseClick.
Vidéo 020.040.20100
Dans ce chapitre, j'ai décidé de vous présenter les évènements avec l'interface graphique pour rendre votre apprentissage plus ludique, mais il faut que vous sachiez que les deux sont totalement dissociés. Il est tout à fait possible d'utiliser des évènements en console par exemple.
D'autre part, comme mentionné dans l'introduction de ce chapitre, vous avez la possibilité de créer vos propres évènements. C'est un peu plus compliqué car il faut voir d'autres notions ; je préfère ainsi vous expliquer cela plus loin dans ce cours.
Dans le chapitre suivant, je vais vous apprendre à travailler avec le temps et nous nous servirons des évènements ; vous devez donc bien les maîtriser. Nous y verrons, avec le contrôle Timer, la notion de parallélisme dans les évènements.

Leave a Reply