Peinture et dessin sur des contrôles (Windows Forms .NET)

La peinture personnalisée des contrôles est l’une des nombreuses tâches complexes facilitées par Windows Forms. Lors de la création d’un contrôle personnalisé, vous disposez de nombreuses options disponibles pour gérer l’apparence graphique de votre contrôle. Si vous créez un contrôle personnalisé, autrement dit, un contrôle qui hérite de Control, vous devez fournir du code pour afficher sa représentation graphique.

Si vous créez un contrôle composite, c’est-à-dire un contrôle qui hérite ou l’un UserControl des contrôles Windows Forms existants, vous pouvez remplacer la représentation graphique standard et fournir votre propre code graphique.

Si vous souhaitez fournir un rendu personnalisé pour un contrôle existant sans créer de contrôle, vos options deviennent plus limitées. Toutefois, il existe toujours un large éventail de possibilités graphiques pour vos contrôles et applications.

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

  • Fonctionnalité de dessin fournie par la classe System.Windows.Forms.Controlde base .
  • Éléments essentiels de la bibliothèque graphique GDI.
  • Géométrie de la zone de dessin.
  • Procédure de libération des ressources graphiques.

Dessin fourni par le contrôle

La classe Control de base fournit des fonctionnalités de dessin par le biais de son Paint événement. 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 .NET, consultez Gestion et déclenchement d’événements.

La classe de données d’événement pour l’événement Paint , PaintEventArgscontient les données nécessaires pour dessiner un contrôle , un handle vers un objet graphique et un rectangle qui représente la région à dessiner.

public class PaintEventArgs : EventArgs, IDisposable
{

    public System.Drawing.Rectangle ClipRectangle {get;}
    public System.Drawing.Graphics Graphics {get;}

    // Other properties and methods.
}
Public Class PaintEventArgs
    Inherits EventArgs
    Implements IDisposable

    Public ReadOnly Property ClipRectangle As System.Drawing.Rectangle
    Public ReadOnly Property Graphics As System.Drawing.Graphics

    ' Other properties and methods.
End Class

Graphics est une classe managée qui encapsule les fonctionnalités de dessin, comme décrit dans la discussion de GDI plus loin dans cet article. Il ClipRectangle s’agit d’une instance de la Rectangle structure et définit la zone disponible dans laquelle un contrôle peut dessiner. Un développeur de contrôles peut calculer l’utilisation ClipRectangle de la ClipRectangle propriété d’un contrôle, comme décrit dans la discussion de la géométrie plus loin dans cet article.

OnPaint

Un contrôle doit fournir une logique de rendu en remplaçant la OnPaint méthode qu’il hérite de Control. OnPaint obtient l’accès à un objet graphique et à un rectangle à dessiner à travers les Graphics propriétés de ClipRectangle l’instance PaintEventArgs passée.

Le code suivant utilise l’espace System.Drawing de noms :

protected override void OnPaint(PaintEventArgs e)
{
    // Call the OnPaint method of the base class.
    base.OnPaint(e);

    // Declare and instantiate a new pen that will be disposed of at the end of the method.
    using var myPen = new Pen(Color.Aqua);

    // Create a rectangle that represents the size of the control, minus 1 pixel.
    var area = new Rectangle(new Point(0, 0), new Size(this.Size.Width - 1, this.Size.Height - 1));

    // Draw an aqua rectangle in the rectangle represented by the control.
    e.Graphics.DrawRectangle(myPen, area);
}
Protected Overrides Sub OnPaint(e As PaintEventArgs)
    MyBase.OnPaint(e)

    ' Declare and instantiate a drawing pen.
    Using myPen = New System.Drawing.Pen(Color.Aqua)

        ' Create a rectangle that represents the size of the control, minus 1 pixel.
        Dim area = New Rectangle(New Point(0, 0), New Size(Me.Size.Width - 1, Me.Size.Height - 1))

        ' Draw an aqua rectangle in the rectangle represented by the control.
        e.Graphics.DrawRectangle(myPen, area)

    End Using
End Sub

La OnPaint méthode de la classe de base Control 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 remplacez OnPaint, vous devez généralement appeler la OnPaint méthode de la classe de base afin que les délégués inscrits reçoivent l’événement Paint . Toutefois, les contrôles qui peintnt toute leur surface ne doivent pas appeler la classe de OnPaintbase, car cela introduit un scintillement.

Remarque

N’appelez OnPaint pas directement à partir de votre contrôle ; appelez plutôt la Invalidate méthode (héritée de ) Controlou une autre méthode qui appelle Invalidate. La Invalidate méthode appelle OnPaintà son tour . La Invalidate méthode est surchargée et, selon les arguments fournis à Invalidate e, redessine une partie ou l’ensemble de sa zone d’écran.

Le code de la OnPaint méthode de votre contrôle s’exécute lorsque le contrôle est dessiné pour la première fois, et chaque fois qu’il est actualisé. Pour vous assurer que votre contrôle est redessiné chaque fois qu’il est redimensionné, ajoutez la ligne suivante au constructeur de votre contrôle :

SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.ResizeRedraw, True)

OnPaintBackground

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

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

OnPaintBackground peint l’arrière-plan (et de cette façon, la forme) de la fenêtre et est garantie d’être rapide, tandis que OnPaint peint les détails et peut être plus lent, car les demandes de peinture individuelles sont combinées en un événement Paint qui couvre toutes les zones qui doivent être redessinées. Vous souhaiterez peut-être appeler si OnPaintBackground , par exemple, vous souhaitez dessiner un arrière-plan de couleur dégradée pour votre contrôle.

Bien qu’elle OnPaintBackground ait une nomenclature de type événement et accepte le même argument que la OnPaint méthode, OnPaintBackground n’est pas une véritable méthode d’événement. Il n’existe aucun PaintBackground événement et OnPaintBackground n’appelle pas de délégués d’événement. En cas de substitution de la OnPaintBackground méthode, une classe dérivée n’est pas nécessaire pour appeler la OnPaintBackground méthode de sa classe de base.

Principes de base de GDI+

La Graphics classe fournit des méthodes pour dessiner différentes formes telles que des cercles, des triangles, des arcs et des points de suspension, et des méthodes pour afficher du texte. L’espace System.Drawing de noms contient des espaces de noms et des classes qui encapsulent des éléments graphiques tels que des formes (cercles, rectangles, arcs et autres), des couleurs, des polices, des pinceaux, etc.

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

La ClientRectangle propriété d’un contrôle spécifie la région rectangulaire disponible pour le contrôle sur l’écran de l’utilisateur, tandis que la ClipRectangle propriété de PaintEventArgs spécifie la zone peinte. Un contrôle peut avoir besoin de peindre uniquement une partie de sa zone disponible, comme c’est le cas lorsqu’une petite section de l’affichage du contrôle change. Dans ces situations, un développeur de contrôles doit calculer le rectangle réel à dessiner et à passer à Invalidate. Les versions surchargées de Invalidate cette prise Rectangle ou Region en tant qu’argument utilisent cet argument pour générer la ClipRectangle propriété de PaintEventArgs.

Libération des ressources graphiques

Les objets graphiques sont coûteux, car ils utilisent des ressources système. Ces objets incluent des instances de la System.Drawing.Graphics classe et des instances de System.Drawing.Brush, System.Drawing.Penet d’autres classes graphiques. Il est important de créer une ressource graphique uniquement quand vous en avez besoin et de la libérer dès que vous avez terminé de l’utiliser. Si vous créez une instance d’un type qui implémente l’interface IDisposable , appelez sa Dispose méthode lorsque vous avez terminé de l’utiliser pour libérer des ressources.

Voir aussi