Criando Janelas não retangulares no Visual Basic .Net
Dê um toque especial em suas aplicações!
Alguma vez você já parou para pensar como programas como o Windows Media Player fazem para criar janelas de formatos não convencionais? Já desejou criar uma janela de abertura ou uma janela de “Sobre...” em suas aplicações que fugisse do padrão usual? Pois no Visual Basic .Net o truque para fazer isso é mais simples do que parece!
Uma das propriedades pouco conhecidas dos formulários no Visual Basic .Net é a propriedade Region. Como o nome sugere, a Region (ou região) é o conjunto de pixels de uma janela onde o sistema operacional tem a permissão de desenhar. Como padrão, esta região é definida como um retângulo do tamanho exato da janela, incluindo a barra de título e as bordas da janela.
Caso a região da janela seja redefinida, o sistema operacional simplesmente não irá desenhar além da nova área definida; assim, se a nova região for definida como um círculo, teremos a ilusão de que criamos uma janela redonda.
A propriedade Region é definida como um conjunto de retângulos e “caminhos gráficos” (uma variável do tipo GraphicsPaths) que define um determinado formato. Um GraphicsPath, por sua vez, pode ser criado a partir de linhas, curvas, retângulos e um conjunto de elementos que vão desde curvas de Bezier até strings (texto). Uma característica interessante da região da janela é que ela não precisa ser contígua, assim, podemos criar uma janela onde diversos elementos flutuam, aparentemente sem estarem conectados.
Para um primeiro teste simples, crie um novo projeto no Visual Basic .Net e adicione o seguinte código ao evento de Load do formulário:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Cria um caminho gráfico composto por uma elipse e uma string
Dim GraphicsPath As New Drawing2D.GraphicsPath
GraphicsPath.AddEllipse(10, 10, 100, 100)
GraphicsPath.AddString("Teste", New FontFamily("Arial"), 1, 20, New Point(130, 130),New StringFormat(StringFormatFlags.NoClip))
Me.Region = New Region(GraphicsPath)
End Sub
Ao executar o programa, veremos que a janela agora tem um novo formato, composto por um círculo e uma string com o texto “Teste”, conforme apresentado na figura 1.

Figura 1 – Uma janela em formato de círculo e com uma string “flutuante”.
Como podemos deduzir imediatamente a partir da figura 1, o primeiro problema que enfrentaremos neste tipo de janela é o que fazer com a sua barra de título pois ela continua a aparecer no topo da região que definimos. Para evitar isto, podemos adotar duas abordagens: Criar uma região que se inicie após a barra de título ou atribuir o valor None à propriedade FormBorderStyle do formulário, o que remove a barra de título da janela. Esta segunda abordagem é preferida pois garante que a barra de título não será apresentada, independente da resolução e configurações de janela do Windows.
Qualquer elemento da região definida através do GraphicsPath é criado a partir de coordenadas da janela, ou seja, o ponto (0,0) é o canto superior esquerdo da barra de título. Cabe lembrar que as coordenadas dos controles que são criados dentro da janela estão em coordenadas da área cliente, ou seja, o ponto (0,0) é o canto superior esquerdo da região de “dentro” da janela, sem contar bordas nem barra de título; assim, caso utilizemos controles em nossas janelas para definir o GraphicsPath, devemos tomar cuidado em fazer a conversão entre coordenadas ou garantir que o formulário não tenha bordas (como explicado no parágrafo anterior), o que torna as coordenadas equivalentes.
Para ilustrar mais um conceito importante, vamos criar dois controles do tipo label em nossa janela, cruzando-se de modo a definir uma cruz, e utilizá-los na definição de nosso GraphicsPath, conforme o código abaixo.
Private Sub Form1_Load(sender As System.Object,e As System.EventArgs) Handles MyBase.Load
' Define uma janela em formato de cruz, a partir de dois labels
Dim GraphicsPath As New Drawing2D.GraphicsPath()
GraphicsPath.AddRectangle(New Rectangle(Label1.Location,Label1.Size))
GraphicsPath.AddRectangle(New Rectangle(Label2.Location,Label2.Size))
Me.Region =New Region(GraphicsPath)
End Sub

Figura 2 – Uma janela em formato de cruz (?), criada com dois labels.
Como podemos ver na figura 2, o resultado não foi bem o esperado: os retângulos definidos pelos labels da janela não criaram uma cruz, mas atuaram de forma subtrativa no local onde havia superposição, gerando uma janela composta por quatro retângulos unidos pelos vértices.
Isto acontece pois a aplicação pode preencher a região interna dos caminhos gráficos de duas maneiras diferentes: alternadamente (que é a forma padrão) ou externamente.
No modo alternado, ou alternate mode, todas as bordas dos elementos que fazem partem do caminho gráfico serão consideradas como limites entre a parte interna e a parte externa da janela; sendo utilizado um algoritmo simples para garantir que todas as áreas são fechadas. Este algoritmo funciona perfeitamente bem com caminhos gráficos que não contenham figuras sobrepostas, ou caso queiramos criar janelas com “buracos” (como as janelas de um carro, ou o exemplo mostrado na Figura 2), mas não funcionará se estamos simplesmente adicionando formatos para criar a região final.
O modo externo, ou winding mode, basicamente pega um ponto de início no caminho gráfico e vai percorrendo as extremidades do caminho, usando um algoritmo simples em cada intersecção que o permite sempre escolher as bordas mais externas da figura.
Adicionando a seguinte linha de código, mudamos o modo de preenchimento do GraphicsPath e conseguiremos fazer com que nossa janela fique em formato de uma cruz completa, conforme o planejado.
Rodando o programa novamente, podemos ver o resultado esperado, como apresentado na figura 3.

Figura 3 – Uma janela em formato de cruz
Explorando os métodos do objeto GraphicsPath, você poderá verificar todo o conjunto de figuras que podem ser utilizadas para a definição da região da janela, permitindo que você adicione aquele “toque a mais” em suas aplicações.
Verifique o artigo sobre Multithreading, onde modificamos o formato padrão de janelas com caminhos gráficos definidos por curvas de Bezier.
Acesse o código fonte deste artigo aqui.
