Académique Documents
Professionnel Documents
Culture Documents
TD n 2 : Composants WinForms
Franck GIL
f.gil@odyssey-services.fr
23/09/2010
TD n 2 : Composants WinForms
INTRODUCTION
Nous allons voir tout ce que vous devez savoir sur les WinForms en crant ensemble (enfin surtout
vous !) un diteur demploi du temps simplifi.
Je sais que ce travail peut paratre long et difficile mais pour une fois a en vaut la peine. Suivez les
instructions jusquau bout, essayez de garder les mmes noms car il y aura des petits bouts de code
recopier. Essayez aussi de ne pas sauter les tapes.
Lancez Visual C# 2010 Express Edition et on y va !
Franck GIL
23 septembre 2010
TD n 2 : Composants WinForms
HELLO WORLD
Commencez par crer une nouvelle application Windows en C#, nous lappellerons EmploiDuTemps.
Par dfaut, lassistant a cr une nouvelle fentre Form1 qui hrite de la classe Form. Celle-ci,
comme tous les composants dinterface, hrite de la classe Control. Chaque contrle peut contenir
des sous-contrles dans sa proprit Controls.
Nous allons ajouter un bouton dans notre fentre. Pour cela, allez dans la boite outils, trouvez le
contrle Button et glissez-le dans votre fentre. Maintenant, double-cliquez sur le bouton pour
gnrer automatiquement la mthode correspondant lvnement du clic.
Si vous regardez le code gnr par le designer dans InitializeComponent() (clic droit sur le nom de la
mthode puis Atteindre la dfinition) , vous verrez comment se construit une page. Vous pourrez
aussi voir comment la mthode button1_Click est branche sur lvnement :
this.button1.Click += new System.EventHandler(this.button1_Click);
2.2
NOS DONNES
Les donnes de notre emploi du temps seront stockes dans une classe RendezVous. Cette classe
contiendra les attributs privs suivants :
_Texte : Informations sur le rendez-vous de type string,
_Debut : Date et heure de type DateTime,
_Duree : Dure en minutes de type int,
_Couleur : La couleur du rendez-vous sur le planning de type Color.
Prenez pour habitude de prfix le nom des attributs par un _, et de lenlever pour dfinir les
proprits de chaque attribut. Pour ajouter un fichier dans le projet, cliquez avec le bouton droit sur
le projet dans lexplorateur de solution. Pour faire propre, vous crirez des proprits pour tous les
attributs de la classe et vous utiliserez la documentation XML (tapez /// au dessus de la classe et des
proprits et laissez-vous guider).
Ensuite, vous crirez 2 constructeurs : un par dfaut et un autre prenant un paramtre pour chaque
attribut de la classe. De plus, la classe devra implmenter linterface Icloneable, qui vous obligera
dfinir la mthode clone comme ci-dessous :
Franck GIL
23 septembre 2010
TD n 2 : Composants WinForms
Pour finir, vous surchargerez la fonction ToString() pour quelle retourne une chane de caractres
avec toutes les informations (sans aller la ligne) :
public override string ToString()
{
return this._Texte + " le " + this._Debut.ToLongDateString() + " "
+ this._Debut.ToLongTimeString()+ " et d'une dure de "
+ this._Duree.ToString() + " minutes";
}
Testez ensuite votre classe dans le code du bouton. Noubliez pas de manire gnrale de compiler
et tester votre code rgulirement.
private void button1_Click(object sender, EventArgs e)
{
RendezVous monRdv = new RendezVous();
monRdv.Texte = "Cours de .Net";
monRdv.Debut = DateTime.Now;
monRdv.Duree = 180;
monRdv.Couleur = Color.Red;
MessageBox.Show(monRdv.ToString());
}
2.3
Nous allons maintenant affichez notre rendez-vous dans une liste. Pour cela, Ajoutez une
ListBox sur le formulaire. Comme la plupart des contrles affichant des donnes, la ListBox contient
une proprit Items qui permet dajouter des lments dans la liste. Dans le code du bouton, nous
allons afficher notre rendez-vous dans la ListBox en lajoutant sa liste des Items.
En ralit cest bien lobjet qui a t ajout la liste des Items. Cest uniquement pour laffichage que
la mthode ToString() a t appele. Malheureusement, elle ne sera pas rappele si tu modifies
lobjet dans la liste sans le raffecter.
Franck GIL
23 septembre 2010
TD n 2 : Composants WinForms
2.4
Dans cette partie, nous allons crer un petit formulaire de saisie pour ajouter, modifier et supprimer
un rendez-vous. Pour cela, ajoutez votre formulaire les composants suivants :
une TextBox pour le texte (Name txtText),
un MonthCalendar pour la date (Name mcDebut et MaxSelectionCount 1),
une TrackBar pour la dure (Name tbDuree, TickFrequency 30, SmallChange 30,
LargeChange 30, Maximum 180 et Minimum 30)
un Label pour afficher la valeur slectionne dans la TrackBar (Name lblDuree),
une TextBox pour la couleur (Name txtColor et Enabled false),
un Button pour ouvrir linterface de slection dune couleur (Name btnColor et Text ),
un ColorDialog pour slectionner une couleur (Name cdColor),
un Button pour ajouter votre rendez-vous (Name btnAjouter et Text Ajouter),
un Button pour modifier votre rendez-vous (Name btnModifier, Enabled false et Text
Modifier),
un Button pour supprimer votre rendez-vous (Name btnSupprimer, Enabled false et Text
Supprimer),
un Button pour annuler la slection de votre rendez-vous (Name btnAnnuler, Enabled
false et Text Annuler).
Franck GIL
23 septembre 2010
TD n 2 : Composants WinForms
Une fois le design du formulaire termin, nous allons surcharger tous les vnements ncessaires au
bon fonctionnement du formulaire. Dans un premier temps, nous allons crer une mthode qui
permet de vider les champs du formulaire pour le mettre dans un tat initial. Nous lutiliserons lors
de la cration de la page.
private void clearFields()
{
txtText.Text = "";
mcDebut.SelectionStart = DateTime.Today;
tbDuree.Value = tbDuree.Minimum;
lblDuree.Text = "Dure: " + tbDuree.Value + " minutes";
txtColor.BackColor = Color.White;
listBox1.SelectedItem = null;
btnAjouter.Enabled = true;
btnModifier.Enabled = false;
btnSupprimer.Enabled = false;
btnAnnuler.Enabled = false;
}
Nous allons modifier le comportement de la TrackBar pour rgler les dplacements du curseur de 30
en 30. Pour cela surchargez lvnement Scroll :
private void tbDuree_Scroll(object sender, EventArgs e)
{
tbDuree.Value = ((int)Math.Round((Double)tbDuree.Value / 30, 0)) * 30;
lblDuree.Text = "Dure: " + tbDuree.Value + " minutes";
}
Ensuite, nous allons permettre la slection de la couleur laide dune ColorDialog. Pour cela doublecliquez sur le bouton pour surcharger lvnement Click :
private void btnColor_Click(object sender, EventArgs e)
{
cdColor.ShowDialog();
txtColor.BackColor = cdColor.Color;
}
Le formulaire fonctionne dsormais correctement. Nous allons raliser maintenant les actions qui
vont permettre de grer lajout, la suppression et la modification dun rendez-vous. Pour raliser ses
actions nous allons surcharger plusieurs vnements de diffrents contrles :
Franck GIL
23 septembre 2010
TD n 2 : Composants WinForms
Franck GIL
23 septembre 2010
TD n 2 : Composants WinForms
Flicitation ! Vous venez de crer votre premier formulaire, testez si toutes vos fonctionnalits
fonctionnent et passez la suite qui savre trs intressante.
Franck GIL
23 septembre 2010
TD n 2 : Composants WinForms
Cette partie, va vous montrez comment crer un contrle rutilisable permettant dafficher et de
manipuler un emploi du temps. Notre exemple reste limit, mais vous pourrez le personnaliser
souhait en y ajoutant de nouvelles fonctionnalits.
3.1
NOUVEAU CONTROLE
Ajoutez votre projet un nouveau contrle utilisateur que vous nommerez EditView. Il hrite de
UserControl. Commencez par y ajouter les attributs publics suivants :
NbJours : Nombre de jour afficher,
DebutJour : Premire heure afficher reprsente par un entier en minutes,
FinJour : Dernire heure afficher reprsente par un entier en minutes,
PremierJour : Premier jour afficher sur lemploi du temps reprsent par un DateTime,
Intervalle : Permet de dfinir des crneaux dans une journe. Il est reprsent par un entier
en minutes,
Marge : De type SizeF qui permet de dfinir une taille 2D,
Selection : De type RendezVous, permet de stocker le rendez-vous slectionn sur le
planning,
Items : contiendra les rendez-vous, il est de type ArrayList.
Nous allons chercher afficher lemploi du temps sous forme de grille. Pour cela, il va falloir dfinir la
largeur dun jour (une colonne) et la hauteur dune minute (une ligne). Il faut donc ajouter 2
proprits qui seront calcules en fonction des autres. Ces deux attributs seront prive, non
modifiable et de type float :
LargeurJour : La largeur totale moins la largeur de la marge, le tout divis par le nombre de
jours,
HauteurMinute : La hauteur totale moins la hauteur de la marge, le tout divis par le nombre
de minutes entre DebutJour et FinJour.
Tous ces attributs seront initialiss dans le constructeur du composant sauf Largeurjour et
HauteurMinute :
public EditView()
{
this.NbJours = 5;
this.DebutJour = 480;
this.FinJour = 1140;
this.PremierJour = DateTime.Today;
this.Marge = new SizeF(48, 32);
this.Selection = null;
this.intervalle = 30;
this.Items = new ArrayList();
InitializeComponent();
}
TD n 2 : Composants WinForms
3.2
Nous allons maintenant afficher une grille qui prendra toute la place disponible (Width, Height)
moins la marge. Tout le code sera dans la classe EditView.
Franck GIL
23 septembre 2010
TD n 2 : Composants WinForms
3.3
DOUBLE BUFFERING
Pour un raffichage fluide (viter les clignotements) il faut activer le double buffering. Ce mcanisme
permet de stocker le contenu du Graphics dans une image pour ne lafficher quune fois termin. On
vite ainsi tout clignotement. Vous devez juste ajouter le code suivant dans le constructeur du
contrle :
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
Franck GIL
23 septembre 2010
10
11
TD n 2 : Composants WinForms
3.4
Comme vous avez pu le constatez, les rendez-vous seront stocks dans Items. On va les afficher dans
la grille sous forme de rectangle avec du texte lintrieur. Pour mettre en place cet affichage,
ralisez une mthode prenant en paramtre lobjet Graphics et un RendezVous :
private void AfficheRDV(RendezVous monRDV, Graphics g)
{
TimeSpan dateTemp = monRDV.Debut.Subtract(PremierJour);
if (dateTemp.Days >= 0 && dateTemp.Hours >= 0 && dateTemp.Minutes >= 0)
{
float x = Marge.Width + (dateTemp.Days * LargeurJour);
float y = Marge.Height + (((monRDV.Debut.Minute +
(monRDV.Debut.Hour * 60) - DebutJour) * HauteurMinute));
RectangleF monRect = new RectangleF(new PointF(x, y),
new SizeF(new PointF(LargeurJour,monRDV.Duree*HauteurMinute)));
g.FillRectangle(new System.Drawing.Drawing2D.LinearGradientBrush(
monRect, monRDV.Couleur, monRDV.Couleur,
System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal),
monRect);
g.DrawRectangle(new Pen(Color.Black), monRect.X, monRect.Y,
monRect.Width, monRect.Height);
g.DrawString(monRDV.ToString(), this.Font,
new SolidBrush(Color.Black) ,new PointF(monRect.X, monRect.Y));
}
}
Franck GIL
23 septembre 2010
TD n 2 : Composants WinForms
Pour tester, vous pouvez arbitrairement ajouter des rendez-vous dans le constructeur dEditView, ou
bien modifier le code de notre ancien diteur. Dans le deuxime cas quelques modifications sont
apporter la surcharge de lvnement Click sur le bouton Ajouter:
private void btnAjouter_Click(object sender, EventArgs e)
{
RendezVous monRdv = new RendezVous();
monRdv.Texte = txtText.Text;
monRdv.Debut = mcDebut.SelectionStart.AddMinutes(editView1.DebutJour);
monRdv.Duree = tbDuree.Value;
monRdv.Couleur = txtColor.BackColor;
editView1.Items.Add(monRdv);
clearFields();
editView1.Invalidate();
}
Faites attention ! La date et lheure des rendez-vous doivent correspondre la grille, sinon cest
normal que cela ne marche pas. De plus, pour forcer le raffichage dun contrle on utilise la
mthode Invaidate() du contrle que lon veut raffich.
3.5
Franck GIL
23 septembre 2010
12
13
TD n 2 : Composants WinForms
surcharge MouseDown : quand lutilisateur appuie avec le bouton droit de la souris, vous
allez rcuprer sa position (e.X, e.Y), et avec elle le rendez-vous concern, puis vous
laffectez lattribut Selection.
private void EditView_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Selection = RecupRdv(e.Location);
this.Invalidate();
}
}
Franck GIL
23 septembre 2010
TD n 2 : Composants WinForms
Note : On ne gre pas ici le fait quil puisse y avoir plusieurs rendez-vous en mme temps.
Il nous reste plus qu ajouter le code suivant la fin de la surcharge de lvnement Paint :
//affiche le RDV selectionn
if (Selection != null)
AfficheRDVSelectione(Selection, e.Graphics);
3.6
A partir de maintenant nous disposons de tous les lments pour raliser lintgration complte du
composant EditView dans notre formulaire de saisie. Quelques modifications sont apporter aux
mthodes et aux surcharges des vnements du formulaire :
La surcharge de lvnement Click sur le bouton modifier :
private void btnModifier_Click(object sender, EventArgs e)
{
RendezVous monRdv = editView1.Selection;
int indice = editView1.Items.IndexOf(monRdv);
monRdv.Texte = txtText.Text;
monRdv.Debut = mcDebut.SelectionStart;
monRdv.Couleur = txtColor.BackColor;
monRdv.Duree = tbDuree.Value;
editView1.Items[indice] = monRdv;
clearFields();
}
La mthode clearFields :
private void clearFields()
{
txtText.Text = "";
mcDebut.SelectionStart = DateTime.Today;
tbDuree.Value = tbDuree.Minimum;
lblDuree.Text = "Dure: " + tbDuree.Value + " minutes";
txtColor.BackColor = Color.White;
editView1.Selection = null;
btnAjouter.Enabled = true;
Franck GIL
23 septembre 2010
14
15
TD n 2 : Composants WinForms
btnModifier.Enabled = false;
btnSupprimer.Enabled = false;
btnAnnuler.Enabled = false;
editView1.Invalidate();
}
Par contre, si vous voulez que lors de la slection dun rendez-vous celui-ci saffiche dans le
formulaire, surchargez lvnement MouseDown du composant EditView mais cette fois-ci du ct
formulaire de saisie :
private void editView1_MouseDown(object sender, MouseEventArgs e)
{
if (editView1.Selection != null)
{
RendezVous monRdv = editView1.Selection;
txtText.Text = monRdv.Texte;
mcDebut.SelectionStart = monRdv.Debut;
tbDuree.Value = monRdv.Duree;
lblDuree.Text = "Dure: " + tbDuree.Value + " minutes";
txtColor.BackColor = monRdv.Couleur;
btnAjouter.Enabled = false;
btnModifier.Enabled = true;
btnSupprimer.Enabled = true;
btnAnnuler.Enabled = true;
}
else
clearFields();
}
3.7
Microsoft, dans son Framework .Net, inclus nativement un mcanisme appel Drag&Drop. Il permet
de bouger la souris des objets dans une application, et mme entre diffrents programmes ! Par
exemple, on va faire en sorte de pouvoir dplacer nos rendez-vous sur notre emploi du temps, glisser
nos rendez-vous vers un calendrier dOutlook et vice-versa.
La premire chose faire est de fixer la proprit AllowDrop true. Les mcanismes de Drag&Drop
et Copier/Coller sont bass sur une structure DataObject. Elle permet de stocker plusieurs versions
de la donne transfre. Ainsi, si on dplace notre objet vers un logiciel de texte, il cherchera sil
contient du texte, si on le dplace vers un logiciel de dessin, il cherchera une image, etc. Nous
allons nous limiter notre type RendezVous et au type Texte.
Ajoutez la dclaration [Serializable] la classe RendezVous (au dessus de la dclaration de cette
classe) ainsi que les mthodes suivantes qui permettront la conversion :
Franck GIL
23 septembre 2010
TD n 2 : Composants WinForms
Pour plus de propret , jai dcid que lobjet ne sera rellement dplac qu la fin du
Drag&Drop. Nous allons crer un objet Tracker qui va garder en mmoire lobjet en cours de
dplacement, ainsi que sa future position. Voici le code de la classe RdvTracker qui correspond ce
mcanisme :
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace EmploiDuTemps
{
class RdvTracker
{
public RendezVous rdv;
public DateTime Debut;
public RdvTracker(RendezVous rdv)
{
this.rdv = rdv;
this.Debut = rdv.Debut;
}
public static RdvTracker FromDataObject(IDataObject obj)
{
RendezVous rdv = RendezVous.FromDataObject(obj);
if (rdv != null)
{
return new RdvTracker(rdv);
}
return null;
}
}
}
Franck GIL
23 septembre 2010
16
17
TD n 2 : Composants WinForms
Ajoutez aussi dans EditView le champ private RdvTracker tracker = null;.Et enfin,
changez la surcharge de lvnement Paint pour quil soit affich. Dessinez-le de faon diffrente du
reste (Transparent par exemple). Noubliez pas quil commence tracker.Debut et non pas
tracker.Rdv.Debut.
Ajoutez ce bout de code la fin la surcharge de lvnement Paint :
//affiche le tracker
if (tracker != null)
AfficheRDVTracker(tracker, e.Graphics);
Enlve tous les vnements souris que tu avais sur le composant EditView, surcharge et recopie les
vnements suivants :
/// <summary>
/// La souris clique: on demarre le dplacement
/// </summary>
private void EditView_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
//Selectionne l'objet sur lequel on est
Selection = RecupRdv(e.Location);
if (Selection != null)// Lance le dplacement
DoDragDrop(Selection.ToDataObject(), DragDropEffects.Move |
DragDropEffects.Copy | DragDropEffects.None);
this.Invalidate();
}
}
/// <summary>
/// Dbut du dplacement: cration du tracker
Franck GIL
23 septembre 2010
TD n 2 : Composants WinForms
/// </summary>
private void EditView_DragEnter(object sender, DragEventArgs e)
{
tracker = RdvTracker.FromDataObject(e.Data);
}
/// <summary>
/// Dplacement en cours sur cet enploi du temps
/// </summary>
private void EditView_DragOver(object sender, DragEventArgs e)
{
//rcupre les coordonnes de la souris dans la fentre
Point loc = PointToClient(new Point(e.X, e.Y));
// Si le tracker existe
if (tracker != null)
{
//rcupre le curseur de copie si la touche Control est appuye ou
//si l'objet en cours de mouvement n'est pas dans lenploi du temps
if (((e.KeyState & 8) == 8 || !Items.Contains(tracker.rdv)))
e.Effect = DragDropEffects.Copy;
else if (loc.X < Marge.Width || loc.Y < Marge.Height)
e.Effect = DragDropEffects.None;
else
e.Effect = DragDropEffects.Move;
// on dplace le tracker mais pas l'objet qu'il contient
if (e.Effect==DragDropEffects.Move||e.Effect==DragDropEffects.Copy)
{
//gestion du chevauchement
DateTime date = QuelleHeureEstIl(loc);
int minute=((date.Minute/intervalle)*intervalle)+60*date.Hour;
if (minute > FinJour - tracker.rdv.Duree)
{
minute = FinJour - tracker.rdv.Duree;
}
date = date.Date.AddMinutes(minute);
RendezVous aComparer = new RendezVous(Selection.Texte, date,
Selection.Duree, Selection.Couleur);
bool seChevauche = false;
foreach (RendezVous rdv in Items)
{
if (rdv != Selection && rdv.SeChevauche(aComparer))
{
seChevauche = true; break;
}
}
if (!seChevauche)
{
tracker.Debut = date.Date;
tracker.Debut = tracker.Debut.AddMinutes(minute);
}
else
e.Effect = DragDropEffects.None;
}
Invalidate();
}
}
/// <summary>
/// On pose l'objet ici
Franck GIL
23 septembre 2010
18
19
TD n 2 : Composants WinForms
/// </summary>
private void EditView_DragDrop(object sender, DragEventArgs e)
{
if (tracker != null)
{
//Si en train de copier: on copie et on ajoute l'objet
if (e.Effect == DragDropEffects.Copy)
{
Selection = tracker.rdv.Clone() as RendezVous;
Items.Add(Selection);
}
// on affecte la nouvelle date (et heure)
Selection.Debut = tracker.Debut;
//on enlve le tracker
tracker = null;
Invalidate();
}
}
/// <summary>
/// Fin du dplacement: n'a pas eu lieu, ou est sorti de la fentre
/// </summary>
private void EditView_DragLeave(object sender, EventArgs e)
{
//on enlve le tracker
tracker = null;
Invalidate();
}
Si vous avez bien fait votre travail, vous devez pouvoir raliser toutes ces oprations :
Slectionner un rendez-vous en lui cliquant dessus.
Dplacer un rendez-vous dans un emploi du temps en le glissant avec la souris.
Copier un rendez-vous dans un emploi du temps en le glissant avec la touche Control
enfonce.
Copier un rendez-vous dans un autre emploi du temps en le glissant avec la souris (mets
pour a un deuxime emploi du temps dans votre fentre).
Glisser du texte depuis un programme quelconque (Word par exemple) vers votre emploi du
temps.
Si vous avez Outlook, essayez aussi de glisser un rendez-vous dans les deux sens.
Franck GIL
23 septembre 2010