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
.NET Desktop feedback