Compartilhar via


Pintura e desenho em controles (Windows Forms .NET)

A pintura personalizada de controles é uma das muitas tarefas complicadas facilitadas pelo Windows Forms. Ao criar um controle personalizado, você tem muitas opções disponíveis para lidar com a aparência gráfica do controle. Se você estiver criando um controle personalizado, ou seja, um controle que herda de Control, deverá fornecer código para renderizar sua representação gráfica.

Se você estiver criando um controle composto, ou seja, um controle que herda de UserControl ou um dos controles existentes do Windows Forms, poderá substituir a representação gráfica padrão e fornecer seu próprio código gráfico.

Se você quiser fornecer renderização personalizada para um controle existente sem criar um novo controle, suas opções se tornarão mais limitadas. No entanto, ainda há uma ampla gama de possibilidades gráficas para seus controles e aplicativos.

Os elementos a seguir estão envolvidos na renderização de controles:

  • A funcionalidade de desenho fornecida pela classe System.Windows.Forms.Controlbase .
  • Os elementos essenciais da biblioteca gráfica GDI.
  • A geometria da região de desenho.
  • O procedimento para liberar recursos gráficos.

Desenho fornecido pelo controle

A classe Control base fornece funcionalidade de desenho por meio de seu Paint evento. Um controle gera o Paint evento sempre que precisa atualizar sua exibição. Para obter mais informações sobre eventos no .NET, consulte Manipulando e gerando eventos.

A classe de dados de evento para o Paint evento, PaintEventArgs, contém os dados necessários para desenhar um controle - um identificador para um objeto gráfico e um retângulo que representa a região a ser desenhada.

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 é uma classe gerenciada que encapsula a funcionalidade de desenho, conforme descrito na discussão sobre GDI mais adiante neste artigo. O ClipRectangle é uma instância da Rectangle estrutura e define a área disponível na qual um controle pode desenhar. Um desenvolvedor de controle pode calcular o ClipRectangle usando a ClipRectangle propriedade de um controle, conforme descrito na discussão sobre geometria mais adiante neste artigo.

OnPaint

Um controle deve fornecer lógica de renderização substituindo o OnPaint método que ele herda de Control. OnPaint obtém acesso a um objeto gráfico e um retângulo para desenhar por meio do Graphics e as ClipRectangle propriedades da PaintEventArgs instância passadas para ele.

O código a seguir usa o System.Drawing namespace:

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

O OnPaint método da classe base Control não implementa nenhuma funcionalidade de desenho, mas apenas invoca os delegados de evento registrados com o Paint evento. Ao substituir OnPainto , você normalmente deve invocar o OnPaint método da classe base para que os delegados registrados recebam o Paint evento. No entanto, os controles que pintam toda a superfície não devem invocar o , da classe OnPaintbase, pois isso introduz cintilação.

Observação

Não invoque OnPaint diretamente do seu controle; em vez disso, invoque o Invalidate método (herdado de Control) ou algum outro método que chame Invalidate. O Invalidate método, por sua vez, OnPaintinvoca . O Invalidate método está sobrecarregado e, dependendo dos argumentos fornecidos ao Invalidate e, redesenha parte ou toda a área da tela.

O código no OnPaint método do seu controle será executado quando o controle for desenhado pela primeira vez e sempre que for atualizado. Para garantir que o controle seja redesenhado sempre que ele for redimensionado, adicione a seguinte linha ao construtor do seu controle:

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

OnPaintBackground

A classe base Control define outro método que é útil para desenhar, o OnPaintBackground método.

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

OnPaintBackground pinta o fundo (e, dessa forma, a forma) da janela e é garantido que será rápido, enquanto OnPaint pinta os detalhes e pode ser mais lento porque as solicitações de pintura individuais são combinadas em um Paint evento que cobre todas as áreas que precisam ser redesenhadas. Talvez você queira invocar o OnPaintBackground se, por exemplo, quiser desenhar um plano de fundo colorido de gradiente para seu controle.

Embora OnPaintBackground tenha uma nomenclatura semelhante a um evento e use o mesmo argumento que o OnPaint método, OnPaintBackground não é um método de evento verdadeiro. Não há nenhum PaintBackground evento e OnPaintBackground não invoca delegados de evento. Ao substituir o OnPaintBackground método, uma classe derivada não é necessária para invocar o OnPaintBackground método de sua classe base.

Noções básicas sobre a GDI+

A Graphics classe fornece métodos para desenhar várias formas, como círculos, triângulos, arcos e elipses, e métodos para exibir texto. O System.Drawing namespace contém namespaces e classes que encapsulam elementos gráficos, como formas (círculos, retângulos, arcos e outros), cores, fontes, pincéis e assim por diante.

Geometria da região de desenho

A ClientRectangle propriedade de um controle especifica a região retangular disponível para o controle na tela do usuário, enquanto a ClipRectangle propriedade de PaintEventArgs especifica a área que é pintada. Um controle pode precisar pintar apenas uma parte da sua área disponível, como é o caso quando uma pequena seção da exibição do controle é alterada. Nessas situações, um desenvolvedor de controle deve calcular o retângulo real para desenhar e passá-lo para Invalidate. As versões sobrecarregadas de Invalidate que usam um Rectangle ou Region como um argumento usam esse argumento para gerar a ClipRectangle propriedade de PaintEventArgs.

Liberando recursos gráficos

Objetos gráficos são caros porque usam recursos do sistema. Esses objetos incluem instâncias da System.Drawing.Graphics classe e instâncias de System.Drawing.Brush, System.Drawing.Pene outras classes gráficas. É importante que você crie um recurso gráfico somente quando precisar dele e libere-o assim que terminar de usá-lo. Se você criar uma instância de um tipo que implementa a IDisposable interface, chame seu Dispose método quando terminar de usá-lo para liberar recursos.

Confira também