Freigeben über


Malen und Zeichnen auf Steuerelementen

Das benutzerdefinierte Zeichnen von Steuerelementen ist eine der vielen komplizierten Aufgaben, die durch Windows Forms vereinfacht werden kann. Wenn ein benutzerdefiniertes Steuerelement erstellt wird, gibt es viele Optionen, wie Sie die grafische Darstellung Ihres Steuerelements beeinflussen können. Wenn Sie ein benutzerdefiniertes Steuerelement erstellen, d. h. ein Steuerelement, das Controlvon diesem erbt, verwenden Sie Code zum Rendern der grafischen Darstellung.

Wenn Sie ein zusammengesetztes Steuerelement erstellen, handelt es sich um ein Steuerelement, das von einem UserControl oder einem der vorhandenen Windows Forms-Steuerelemente erbt, können Sie die standardmäßige grafische Darstellung außer Kraft setzen und Ihren eigenen Grafikcode bereitstellen.

Wenn Sie ein benutzerdefiniertes Rendering für ein vorhandenes Steuerelement bereitstellen möchten, ohne ein neues Steuerelement zu erstellen, behandeln Sie das Paint Ereignis, mit dem Sie über ein Steuerelement zeichnen können.

Beim Rendern von Steuerelementen sind die folgenden Elemente beteiligt:

  • Die von der Basisklasse System.Windows.Forms.Control bereitgestellte Funktion zum Zeichnen
  • Die essentiellen Elemente der GDI-Grafikbibliothek
  • Die Geometrie der Zeichnungsregion
  • Die Prozedur für das Freigeben von Grafikressourcen

Vom Steuerelement bereitgestellte Funktionen zum Zeichnen

Die Basisklasse Control stellt Funktionen zum Zeichnen über das dazugehörige Paint-Ereignis bereit. Ein Steuerelement löst das Paint Ereignis aus, wenn es seine Anzeige aktualisieren muss und seine Zeichnung ausgeführt hat. Weitere Informationen zu Ereignissen in .NET finden Sie unter Behandeln und Auslösen von Ereignissen.

Die Ereignisdatenklasse für das Paint-Ereignis, PaintEventArgs, enthält die Daten, die für das Zeichnen eines Steuerelements erforderlich sind – ein Handle für ein Grafikobjekt und ein Rechteck, das die Region darstellt, in der gezeichnet wird.

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 ist eine verwaltete Klasse, die die Funktion zum Zeichnen kapselt. Weitere Informationen finden Sie in der GDI-Diskussion später in diesem Artikel. Bei ClipRectangle handelt es sich um eine Instanz der Rectangle-Struktur. Hierdurch wird der verfügbare Bereich definiert, in dem ein Steuerelement zeichnen kann. Der Entwickler eines Steuerelements kann ClipRectangle mit der ClipRectangle-Eigenschaft eines Steuerelements berechnen. Weitere Informationen finde Sie in der Geometriediskussion später in diesem Artikel.

OnPaint

Ein Steuerelement muss Renderinglogik bereitstellen, indem die OnPaint-Methode überschrieben wird, die es von Control erbt. OnPaint erhält über die übergebenen Eigenschaften Graphics und ClipRectangle der Instanz PaintEventArgs Zugriff auf ein Grafikobjekt und ein Rechteck, in dem gezeichnet werden kann.

Im folgenden Code wird der System.Drawing-Namespace verwendet:

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

Die OnPaint-Methode der Control-Basisklasse implementiert keine Zeichnungsfunktionen, ruft jedoch die Ereignisdelegaten auf, die für das Paint-Ereignis registriert sind. Wenn Sie OnPaint überschreiben, sollten Sie in der Regel die OnPaint-Methode der Basisklasse aufrufen, damit registrierte Delegaten das Paint-Ereignis empfangen. Allerdings sollten Steuerelemente, die ihre gesamte Oberfläche zeichnen, die Basisklasse OnPaint nicht aufrufen, da dies Flimmern verursacht.

Hinweis

Rufen Sie OnPaint nicht direkt in Ihrem Steuerelement auf. Rufen Sie stattdessen die Invalidate-Methode (von Control geerbt) oder eine andere Methode auf, die Invalidate aufruft. Die Invalidate-Methode wiederum ruft OnPaint auf. Die Invalidate-Methode wird überladen und zeichnet je nach für Invalidatee bereitgestellten Argumenten entweder Teile oder den gesamten Bildschirmbereich neu.

Der Code in der OnPaint-Methode Ihres Steuerelements wird ausgeführt, wenn das Steuerelement erstmalig gezeichnet wird, und bei jeder Aktualisierung. Damit Ihr Steuerelement bei jeder Größenanpassung neu gezeichnet wird, fügen Sie die folgende Zeile im Konstruktor Ihres Steuerelements hinzu:

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

OnPaintBackground

Die Control-Basisklasse definiert eine weitere Methode, die hilfreich für das Zeichnen ist: die OnPaintBackground-Methode.

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

OnPaintBackground zeichnet den Hintergrund (und so auch die Form) des Fensters. Dies erfolgt sehr schnell. OnPaint hingegen zeichnet die Details und ist deshalb möglicherweise langsamer, da einzelne Zeichnungsanforderungen in ein Paint-Ereignis kombiniert werden, das alle Bereiche abdeckt, die neu gezeichnet werden müssen. Sie sollten OnPaintBackground aufrufen, wenn Sie beispielsweise ein Hintergrund mit Farbverlauf für Ihr Steuerelement zeichnen möchten.

Während OnPaintBackground eine ereignisähnliche Bezeichnung aufweist und dasselbe Argument wie die OnPaint-Methode annimmt, handelt es sich bei OnPaintBackground um keine tatsächliche Ereignismethode. Es gibt kein PaintBackground-Ereignis, und OnPaintBackground ruft keine Ereignisdelegaten auf. Wenn die OnPaintBackground-Methode überschrieben wird, ist keine abgeleitete Klasse erforderlich, um die OnPaintBackground-Methode der dazugehörigen Basisklasse aufzurufen.

GDI+-Grundlagen

Die Graphics-Klasse bietet Methoden für das Zeichnen verschiedener Formen wie Kreise, Dreiecke, Bögen und Ellipsen sowie Methoden für das Anzeigen von Text. Der System.Drawing-Namespace enthält Namespaces und Klassen, die grafische Elemente wie Formen (z. B. Kreise, Rechtecke und Bögen), Farben, Schriftarten und Pinsel kapseln.

Geometrie der Zeichnungsregion

Die ClientRectangle-Eigenschaft eines Steuerelements gibt die rechteckige Region an, die für das Steuerelement auf der Anzeige für den Benutzer verfügbar ist. Die ClipRectangle-Eigenschaft von PaintEventArgs gibt dahingegen den Bereich an, der gezeichnet wird. Ein Steuerelement muss möglicherweise nur einen Teil des verfügbaren Bereichs zeichnen, z. B. wenn ein kleiner Bereich der Anzeige des Steuerelements geändert wird. In solchen Situationen muss der Entwickler eines Steuerelements das tatsächliche Rechteck berechnen, in dem gezeichnet werden soll, und dieses an Invalidate übergeben. Die überladenen Versionen von Invalidate, die Rectangle oder Region als Argument akzeptieren, verwenden dieses Argument, um die ClipRectangle-Eigenschaft von PaintEventArgs zu generieren.

Freigeben von Grafikressourcen

Grafikobjekte sind teuer, da sie Systemressourcen verwenden. Zu solchen Objekten gehören Instanzen der System.Drawing.Graphics-Klasse und Instanzen von System.Drawing.Brush, System.Drawing.Pen sowie weitere Grafikklassen. Es ist wichtig, dass Sie eine Grafikressource nur dann erstellen, wenn Sie sie benötigen, und sie freigeben, sobald Sie sie nicht mehr benötigen. Wenn Sie eine Instanz eines Typs erstellen, der die IDisposable-Schnittstelle implementiert, rufen Sie die dazugehörige Dispose-Methode auf, sobald Sie das Freigeben der Ressourcen abgeschlossen haben.

Siehe auch

Benutzerdefinierte Steuerelemente