Malowanie i rysowanie na kontrolkach (Windows Forms .NET)

Niestandardowy obraz kontrolek jest jednym z wielu skomplikowanych zadań ułatwianych przez formularze systemu Windows. Podczas tworzenia kontrolki niestandardowej dostępnych jest wiele opcji obsługi graficznego wyglądu kontrolki. Jeśli tworzysz kontrolkę niestandardową, oznacza to, że kontrolka dziedzicząca z Controlelementu , musisz podać kod, aby renderować jego graficzną reprezentację.

Jeśli tworzysz kontrolkę złożoną, to jest to kontrolka dziedziczona z UserControl lub jednej z istniejących kontrolek Windows Forms, możesz zastąpić standardową graficzną reprezentację i podać własny kod graficzny.

Jeśli chcesz udostępnić renderowanie niestandardowe dla istniejącej kontrolki bez tworzenia nowej kontrolki, opcje stają się bardziej ograniczone. Jednak nadal istnieje wiele możliwości graficznych dla kontrolek i aplikacji.

Następujące elementy są zaangażowane w renderowanie kontrolek:

  • Funkcje rysunku udostępniane przez klasę System.Windows.Forms.Controlbazową .
  • Podstawowe elementy biblioteki grafiki GDI.
  • Geometria regionu rysunku.
  • Procedura zwalniania zasobów graficznych.

Rysunek dostarczony przez kontrolkę

Klasa Control podstawowa udostępnia funkcje rysowania za pośrednictwem jego Paint zdarzenia. Kontrolka Paint wywołuje zdarzenie za każdym razem, gdy musi zaktualizować jego ekran. Aby uzyskać więcej informacji na temat zdarzeń na platformie .NET, zobacz Obsługa i zgłaszanie zdarzeń.

Klasa danych zdarzenia dla Paint zdarzenia PaintEventArgs, przechowuje dane potrzebne do rysowania kontrolki — uchwyt do obiektu graficznego i prostokąt reprezentujący region do rysowania.

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 jest klasą zarządzaną, która hermetyzuje funkcje rysowania, zgodnie z opisem w dalszej części tego artykułu. Jest ClipRectangle to wystąpienie Rectangle struktury i definiuje dostępny obszar, w którym kontrolka może rysować. Deweloper kontrolki może obliczyć ClipRectangle przy użyciu ClipRectangle właściwości kontrolki, zgodnie z opisem w dalszej części tego artykułu.

OnPaint

Kontrolka musi zapewnić logikę renderowania, przesłaniając metodę OnPaint dziedziczącą z Controlklasy . OnPaint uzyskuje dostęp do obiektu graficznego i prostokąta do rysowania za pomocą Graphics właściwości i ClipRectangle przekazanych PaintEventArgs do niego właściwości wystąpienia.

Poniższy kod używa System.Drawing przestrzeni nazw:

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

Metoda OnPaint klasy bazowej Control nie implementuje żadnych funkcji rysowania, ale jedynie wywołuje delegatów zdarzeń zarejestrowanych w Paint zdarzeniu. Po zastąpieniu OnPaintmetody zazwyczaj należy wywołać OnPaint metodę klasy bazowej, aby zarejestrowani delegaci otrzymywali Paint zdarzenie. Jednak kontrolki, które malują całą powierzchnię, nie powinny wywoływać klasy bazowej OnPaint, ponieważ wprowadza to migotanie.

Uwaga

Nie należy wywoływać OnPaint bezpośrednio z kontrolki; zamiast tego wywołaj metodę Invalidate (dziedziczona z Controlklasy ) lub inną metodę, która wywołuje Invalidatemetodę . Metoda Invalidate z kolei wywołuje metodę OnPaint. Metoda Invalidate jest przeciążona i, w zależności od argumentów dostarczonych do Invalidate e, ponownie rysuje część lub cały jej obszar ekranu.

Kod w OnPaint metodzie kontrolki zostanie wykonany po pierwszym narysowanym kontrolce i za każdym razem, gdy zostanie odświeżony. Aby upewnić się, że kontrolka jest ponownie rysowana przy każdej zmianie rozmiaru, dodaj następujący wiersz do konstruktora kontrolki:

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

OnPaintBackground

Klasa bazowa Control definiuje inną metodę, która jest przydatna OnPaintBackground do rysowania metody .

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

OnPaintBackground maluje tło (i w ten sposób kształt) okna i gwarantuje szybkość, podczas gdy OnPaint maluje szczegóły i może być wolniejsze, ponieważ poszczególne żądania farby są łączone w jedno Paint zdarzenie, które obejmuje wszystkie obszary, które muszą być ponownie rysowane. Możesz wywołać metodę OnPaintBackground , jeśli na przykład chcesz narysować tło w kolorze gradientu dla kontrolki.

Chociaż OnPaintBackground ma nomenklaturę podobną do zdarzenia i przyjmuje ten sam argument co OnPaint metoda, OnPaintBackground nie jest to prawdziwa metoda zdarzenia. Brak zdarzenia PaintBackground i OnPaintBackground nie wywołuje delegatów zdarzeń. Podczas zastępowania OnPaintBackground metody klasa pochodna nie jest wymagana do wywołania OnPaintBackground metody klasy bazowej.

GDI+ Podstawy

Klasa Graphics udostępnia metody rysowania różnych kształtów, takich jak okręgi, trójkąty, łuki i wielokropek oraz metody wyświetlania tekstu. System.Drawing Przestrzeń nazw zawiera przestrzenie nazw i klasy, które hermetyzują elementy graficzne, takie jak kształty (okręgi, prostokąty, łuki i inne), kolory, czcionki, pędzle itd.

Geometria regionu rysunku

Właściwość ClientRectangle kontrolki określa prostokątny region dostępny dla kontrolki na ekranie użytkownika, podczas gdy ClipRectangle właściwość PaintEventArgs określa obszar, który jest malowany. Kontrolka może wymagać malowania tylko części dostępnego obszaru, tak jak w przypadku zmiany małej części ekranu kontrolki. W takich sytuacjach deweloper kontroli musi obliczyć rzeczywisty prostokąt, aby narysować obiekt i przekazać go do Invalidateelementu . Przeciążone wersje Invalidate elementu , które przyjmują Rectangle argument lub Region jako argument, używają tego argumentu do wygenerowania ClipRectangle właściwości PaintEventArgs.

Zwalnianie zasobów graficznych

Obiekty graficzne są kosztowne, ponieważ używają zasobów systemowych. Takie obiekty obejmują wystąpienia System.Drawing.Graphics klasy i wystąpień System.Drawing.Brushklasy , System.Drawing.Peni innych klas graficznych. Ważne jest, aby utworzyć zasób graficzny tylko wtedy, gdy jest potrzebny i zwolnić go zaraz po zakończeniu korzystania z niego. Jeśli utworzysz wystąpienie typu implementujące interfejs, wywołaj jego Dispose metodę po zakończeniu IDisposable pracy z nim, aby zwolnić zasoby.

Zobacz też