Renderizando um controle dos Windows Forms

Renderização se refere ao processo de criar uma representação visual na tela do usuário. O Windows Forms usa GDI (a nova biblioteca de elementos gráficos do Windows) para renderização. As classes gerenciadas que fornecem acesso ao GDI estão no System.Drawing namespace e em seus subnamespaces.

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.

Funcionalidade de desenho fornecida pelo controle

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

A classe de dados do evento para o Paint evento, , PaintEventArgscontém os dados necessários para desenhar um controle — um identificador para um objeto gráfico e um objeto retangular que representa a região a ser desenhada. Esses objetos são mostrados em negrito no seguinte fragmento de código.

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 é uma classe gerenciada que encapsula a funcionalidade de desenho, conforme descrito na discussão do GDI mais adiante neste tópico. 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 uso ClipRectangle da propriedade de um controle, conforme descrito na discussão de geometria mais adiante neste tópico.

Um controle deve fornecer lógica de renderização substituindo o OnPaint método que ele herda do Control. OnPaint Obtém acesso a um objeto gráfico e a um retângulo para desenhar através das Graphics propriedades e da ClipRectanglePaintEventArgs instância passada para ele.

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

O OnPaint método da classe base Control não implementa nenhuma funcionalidade de desenho, mas apenas invoca os delegados de evento que estão 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 a classe OnPaintbase, pois isso introduz a cintilação. Para obter um exemplo de substituição do evento, consulte Como: Criar um controle do Windows Forms que mostra o OnPaintprogresso.

Observação

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

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

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

OnPaintBackground pinta o fundo (e, portanto, a forma) da janela e é garantido que seja 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 abrange todas as áreas que precisam ser redesenhadas. Talvez você queira invocar o OnPaintBackground se, por exemplo, você deseja desenhar um plano de fundo colorido de gradiente para seu controle.

Embora OnPaintBackground tenha uma nomenclatura semelhante a um evento e tenha 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 método, uma classe derivada não é necessária para invocar o OnPaintBackgroundOnPaintBackground 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, bem como métodos para exibir texto. O System.Drawing namespace e seus subnamespaces contêm classes que encapsulam elementos gráficos, como formas (círculos, retângulos, arcos e outros), cores, fontes, pincéis e assim por diante. Para obter mais informações sobre GDI, consulte Usando classes de gráficos gerenciados. Os fundamentos do GDI também são descritos em Como: Criar um controle do Windows Forms que mostra o progresso.

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 propriedade de PaintEventArgs especifica a ClipRectangle área que é realmente pintada. (Lembre-se de que a Paint pintura é feita no método de evento que toma uma PaintEventArgs instância como argumento). 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 passar isso para Invalidate. As versões sobrecarregadas Invalidate que usam um ou Region como um Rectangle argumento usam esse argumento para gerar a ClipRectangle propriedade de PaintEventArgs.

O fragmento de código a seguir mostra como o controle personalizado FlashTrackBar calcula a área retangular na qual desenhar. A client variável denota a ClipRectangle propriedade. Para ver um exemplo completo, consulte Como criar um controle do Windows Forms que mostre o progresso.

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

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

Invalidate(invalid)

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, bem como instâncias de , System.Drawing.Pene outras classes gráficasSystem.Drawing.Brush. É importante que você crie um recurso de gráfico somente quando precisar dele e o libere assim que terminar de usá-lo. Se você criar um tipo que implementa a IDisposable interface, chame seu Dispose método quando terminar de usá-lo para liberar recursos.

O fragmento de código a seguir mostra como o FlashTrackBar controle personalizado cria e libera um Brush recurso. Para ver o código-fonte completo, consulte Como criar um controle do Windows Forms que mostre o progresso.

private Brush baseBackground = null;
Private baseBackground As Brush
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);
    }
}
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 (BackgroundImage IsNot Nothing) Then
        baseBackground = New TextureBrush(BackgroundImage)
    Else
        baseBackground = New SolidBrush(BackColor)
    End If

End If
protected override void OnResize(EventArgs e) {
    base.OnResize(e);
    if (baseBackground != null) {
        baseBackground.Dispose();
        baseBackground = null;
    }
}
Protected Overrides Sub OnResize(ByVal e As EventArgs)
    MyBase.OnResize(e)
    If (baseBackground IsNot Nothing) Then
        baseBackground.Dispose()
        baseBackground = Nothing
    End If
End Sub

Confira também