Partilhar via


Renderização de um controlo do Windows Forms

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

Os seguintes elementos estão envolvidos na renderização de controle:

  • A funcionalidade de desenho fornecida pela classe base System.Windows.Forms.Control.

  • 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 base Control fornece funcionalidade de desenho por meio de seu evento Paint. Um controle aciona o evento Paint sempre que precisa atualizar sua exibição. Para obter mais informações sobre eventos no .NET Framework, consulte Manipulando e levantando eventos.

A classe de dados de evento para o evento Paint, PaintEventArgs, conté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 fragmento de código a seguir.

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 estrutura Rectangle e define a área disponível na qual um controle pode desenhar. Um desenvolvedor de controle pode calcular o ClipRectangle usando a propriedade ClipRectangle de um controle, conforme descrito na discussão sobre geometria mais adiante neste tópico.

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

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

O método OnPaint da classe Control base não implementa nenhuma funcionalidade de desenho, mas apenas invoca os delegados de evento registrados com o evento Paint. Quando deve substituir OnPaint, normalmente deve invocar o método da classe base OnPaint para que os delegados registados recebam o evento Paint. No entanto, os controles que pintam toda a superfície não devem invocar o OnPaintda classe base, pois isso introduz cintilação. Para obter um exemplo de substituição do evento OnPaint, consulte Como: Criar um controle do Windows Forms para mostrar o progresso.

Observação

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

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

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 será rápido, enquanto OnPaint pinta os detalhes e pode ser mais lento porque os pedidos de pintura individuais são combinados em um evento Paint que cobre todas as áreas que precisam ser redesenhadas. Você pode querer invocar o OnPaintBackground se, por exemplo, quiser desenhar um plano de fundo colorido em gradiente para o seu controlo.

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

Noções básicas do GDI+

A classe Graphics fornece métodos para desenhar várias formas, como círculos, triângulos, arcos e elipses, bem como métodos para exibir texto. O namespace System.Drawing 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 gráficas gerenciadas. Os fundamentos do GDI também são descritos na Como Fazer para: Criar um controle do Windows Forms que mostra o progresso.

Geometria da Região de Desenho

A propriedade ClientRectangle de um controle especifica a região retangular disponível para o controle na tela do usuário, enquanto a propriedade ClipRectangle de PaintEventArgs especifica a área que é realmente pintada. (Lembre-se de que a pintura é feita no método de evento Paint que toma uma instância PaintEventArgs como argumento). Um controle pode precisar pintar apenas uma parte de sua área disponível, como é o caso quando uma pequena seção da exibição do controle muda. Nessas situações, um desenvolvedor de controle deve calcular o retângulo real para desenhar e passar isso para Invalidate. As versões sobrecarregadas de Invalidate que recebem um Rectangle ou Region como argumento usam esse argumento para gerar a propriedade ClipRectangle de PaintEventArgs.

O fragmento de código a seguir mostra como o controle personalizado FlashTrackBar calcula a área retangular para desenhar. A variável client denota a propriedade ClipRectangle. Para obter um exemplo completo, consulte Como criar um controle do Windows Forms que mostra 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

Os objetos gráficos são caros porque usam recursos do sistema. Esses objetos incluem instâncias da classe System.Drawing.Graphics, bem como 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 o libere assim que terminar de usá-lo. Se você criar um tipo que implementa a interface IDisposable, chame seu método Dispose quando terminar de usá-lo para liberar recursos.

O fragmento de código a seguir mostra como o controle personalizado FlashTrackBar cria e libera um recurso Brush. Para obter o código-fonte completo, consulte Como criar um controle do Windows Forms que mostra 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

Ver também