Rendu d'un contrôle Windows Forms

Le rendu désigne le processus de création d'une représentation visuelle sur l'écran de l'utilisateur. Windows Forms utilise GDI (la nouvelle bibliothèque de graphiques Windows) pour le rendu. Les classes managées qui donnent accès à GDI se trouvent dans l'espace de noms System.Drawing et ses sous-espaces de noms.

Les éléments suivants sont impliqués dans le rendu du contrôle :

  • Fonctionnalités de dessin fournies par la classe de base System.Windows.Forms.Control.

  • Éléments essentiels de la bibliothèque de graphiques GDI.

  • Géométrie de la région de dessin.

  • Procédure permettant de libérer les ressources graphiques.

Fonctionnalités de dessin fournies par le contrôle

La classe de base Control fournit des fonctionnalités de dessin à l'aide de son événement Paint. Un contrôle déclenche l'événement Paint chaque fois qu'il doit mettre à jour son affichage. Pour plus d'informations sur les événements dans le .NET Framework, consultez Gestion et déclenchement d'événements.

La classe de données d'événement pour l'événement Paint, PaintEventArgs, contient les données nécessaires pour dessiner un contrôle (un handle pour un objet graphique et un objet rectangle qui représente la région du dessin). Ces objets sont indiqués en gras dans le fragment de code suivant :

Public Class PaintEventArgs
   Inherits EventArgs
   Implements IDisposable
   
   Public ReadOnly Property ClipRectangle() As System.Drawing.Rectangle
      ...
   End Property
   
   Public ReadOnly Property Graphics() As System.Drawing.Graphics
      ...
   End Property
   ' Other properties and methods.
   ...
End Class
public class PaintEventArgs : EventArgs, IDisposable {
public System.Drawing.Rectangle ClipRectangle {get;}
public System.Drawing.Graphics Graphics {get;}
// Other properties and methods.
...
}

Graphics est une classe managée qui encapsule les fonctionnalités de dessin, telles qu'elles sont décrites dans l'explication de GDI, plus loin dans cette rubrique. ClipRectangle est une instance de la classe Rectangle et définit la zone disponible dans laquelle un contrôle peut être dessiné. Un développeur de contrôles peut calculer ClipRectangle à l'aide de la propriété ClipRectangle d'un contrôle, comme décrit dans l'explication de la géométrie, plus loin dans cette rubrique.

Un contrôle doit fournir le rendu logique en substituant la méthode OnPaint qu'il hérite de Control. OnPaint donne accès à un objet Graphics et un rectangle à dessiner via les propriétés Graphics et les propriétés ClipRectangle de l'instance de PaintEventArgs qui lui est passée.

Protected Overridable Sub OnPaint(pe As PaintEventArgs)
protected virtual void OnPaint(PaintEventArgs pe);

La méthode OnPaint de la classe Control de base n'implémente aucune fonctionnalité de dessin, mais appelle simplement les délégués d'événement inscrits auprès de l'événement Paint. Lorsque vous substituez OnPaint, vous devez généralement appeler la méthode OnPaint de la classe de base de sorte que les délégués inscrits reçoivent l'événement Paint. Cependant, les contrôles qui peignent la totalité de leur surface ne doivent pas appeler la méthode OnPaint de la classe de base, car cela entraîne du scintillement. Pour obtenir un exemple de substitution de l'événement OnPaint, consultez le Comment : créer un contrôle Windows Forms qui affiche la progression.

Notes

N'appelez pas OnPaint directement à partir de votre contrôle. Appelez plutôt la méthode Invalidate (héritée de Control) ou toute autre méthode appelant Invalidate. La méthode Invalidate appelle à son tour OnPaint. La méthode Invalidate est surchargée et, selon les arguments fournis à Invalidate e, un contrôle redessine une partie ou la totalité de sa zone d'affichage.

La classe Control de base définit une autre méthode utile pour le dessin : la méthode OnPaintBackground.

Protected Overridable Sub OnPaintBackground(pevent As PaintEventArgs)
protected virtual void OnPaintBackground(PaintEventArgs pevent);

OnPaintBackground peint l'arrière-plan (et donc la forme) de la fenêtre et sa rapidité est garantie, alors que OnPaint peint les détails et peut être plus lent, car les demandes de peinture individuelles sont combinées dans un événement Paint qui couvre toutes les zones à redessiner. Il est possible d'appeler OnPaintBackground si, par exemple, vous souhaitez dessiner un arrière-plan en couleurs dégradées pour votre contrôle.

Alors que OnPaintBackground possède une nomenclature de type événement et prend le même argument que la méthode OnPaint, OnPaintBackground n'est pas une véritable méthode d'événements. Il n'existe aucun événement PaintBackground et OnPaintBackground n'appelle pas de délégués d'événements. Lors de la substitution de la méthode OnPaintBackground, une classe dérivée n'est pas obligée d'appeler la méthode OnPaintBackground de sa classe de base.

Concepts de base de GDI+

La classe Graphics fournit des méthodes pour le dessin de diverses formes, telles que des cercles, des triangles, des arcs et des ellipses, ainsi que des méthodes pour l'affichage de texte. L'espace de noms System.Drawing et ses sous-espaces de noms contiennent des classes qui encapsulent des éléments graphiques, tels que des formes (cercles, rectangles, arcs, etc.), des couleurs, des polices, des pinceaux, etc. Pour plus d'informations sur GDI, consultez Utilisation de classes graphiques managées. Les qualités indispensables de GDI sont également décrites dans le Comment : créer un contrôle Windows Forms qui affiche la progression.

Géométrie de la région de dessin

La propriété ClientRectangle d'un contrôle spécifie la région rectangulaire mise à la disposition du contrôle sur l'écran de l'utilisateur, alors que la propriété ClipRectangle de PaintEventArgs spécifie la zone réellement peinte. (N'oubliez pas que la peinture est effectuée dans la méthode Paint qui prend comme argument une instance de PaintEventArgs.) Il se peut qu'un contrôle ne doive peindre qu'une partie de sa zone disponible, comme c'est le cas lorsqu'une petite section de l'affichage du contrôle est modifiée. Dans ce cas, un développeur de contrôles doit calculer le rectangle réel dans lequel effectuer le dessin et le passer à Invalidate. Les versions surchargées de Invalidate qui prend un Rectangle ou Region comme argument utilisent cet argument pour générer la propriété ClipRectangle de PaintEventArgs.

Le fragment de code suivant montre comment le contrôle personnalisé FlashTrackBar calcule la zone rectangulaire dans laquelle effectuer le dessin. La variable client désigne la propriété ClipRectangle. Pour l'exemple complet, consultez Comment : créer un contrôle Windows Forms qui affiche la progression.

Dim invalid As Rectangle = New Rectangle( _
    client.X + lmin, _
    client.Y, _
    lmax - lmin, _
    client.Height)

Invalidate(invalid)
Rectangle invalid = new Rectangle(
    client.X + min, 
    client.Y, 
    max - min, 
    client.Height);

Invalidate(invalid);

Libération des ressources graphiques

Les objets graphiques sont coûteux, car ils utilisent les ressources système. De tels objets incluent des instances de la classe System.Drawing.Graphics aussi bien que des instances de System.Drawing.Brush, System.Drawing.Pen et d'autres classes de graphiques. Veillez à ne créer une ressource graphique qu'en cas de nécessité et à la libérer dès que vous avez terminé de l'utiliser. Si vous créez un type qui implémente l'interface IDisposable, appelez sa méthode Dispose lorsque vous avez terminé de l'utiliser afin de libérer des ressources.

Le fragment de code suivant montre comment le contrôle personnalisé FlashTrackBar crée et libère une ressource Brush. Pour le code source complet, consultez Comment : créer un contrôle Windows Forms qui affiche la progression.

Private baseBackground As Brush
private Brush baseBackground = null;
MyBase.OnPaint(e)

If (baseBackground Is Nothing) Then

    If (myShowGradient) Then
        baseBackground = New LinearGradientBrush(New Point(0, 0), _
                                                 New Point(ClientSize.Width, 0), _
                                                 StartColor, _
                                                 EndColor)
    ElseIf Not (BackgroundImage Is Nothing) Then
        baseBackground = New TextureBrush(BackgroundImage)
    Else
        baseBackground = New SolidBrush(BackColor)
    End If

End If
base.OnPaint(e);
if (baseBackground == null) {
    if (showGradient) {
        baseBackground = new LinearGradientBrush(new Point(0, 0),
                                                 new Point(ClientSize.Width, 0),
                                                 StartColor,
                                                 EndColor);
    }
    else if (BackgroundImage != null) {
        baseBackground = new TextureBrush(BackgroundImage);
    }
    else {
        baseBackground = new SolidBrush(BackColor);
    }
}
Protected Overrides Sub OnResize(ByVal e As EventArgs)
    MyBase.OnResize(e)
    If Not (baseBackground Is Nothing) Then
        baseBackground.Dispose()
        baseBackground = Nothing
    End If
End Sub
protected override void OnResize(EventArgs e) {
    base.OnResize(e);
    if (baseBackground != null) {
        baseBackground.Dispose();
        baseBackground = null;
    }
}

Voir aussi

Tâches

Comment : créer un contrôle Windows Forms qui affiche la progression