Artigo Clube Delphi Edição 10 - Invisíveis e Transparentes
Artigo da Revista Clube Delphi Edição 10.
Peter Norton foi o guru de muitos programadores de minha geração. Com suas obras especializadas, contribuiu para formar muitos de meus conceitos, alguns renovados com as novas tecnologias, outros resistentes ao tempo.
A chuva de obras publicadas em seu nome, me deixaram confuso, será que foi ele quem realmente escreveu todos? Baseado em assuntos bem variados, eu comecei a fazer algumas contas: Pelo menos 1 ano para formar conceitos sólidos sobre o assunto e mais seis meses no mínimo para escrever um livro com 250 a 300 páginas. Seria impossível comparado ao número de títulos. Já seus aplicativos, temos certeza que foi uma grande equipe.
Com a revolução visual pós Windows 95, muitos aplicativos começaram a chamar a atenção pelas telas de splash (tela inicial enquanto o programa é carregado). O Norton Crash Guard, com seu splash em forma de escudo me fascinou. Pensei: Tenho que imitá-lo!
A forma mais simples seria arrumar um bitmap com fundo transparente, na forma desejada, e colocar o form transparente também alterando sua propriedade brush, e finalmente esconder o caption do form.
Form1.Brush.Style := bsclear;
Trabalhoso, mas mais trabalhoso ainda é fazer isto utilizando funções APIs. Porém, este é o nosso desafio!
O problema do código acima é que ele não atualiza a área transparente, e não adianta dar um simples Invalidate em um evento qualquer - chega de "gambiarras", vamos escrever uma solução definitiva. O efeito do form transparente é executado pelo princípio de Regiões. Primeiro crie uma região que cerca o form inteiro. Então, ache a área de cliente da forma (Client vs. non-Client). Após isto basta mostrar ou esconder o form, preocupando-se com o refresh da parte invisível, ou seja, atualizar o fundo em caso de você mover o form. Vamos para a prática !
Var
Form1: TForm1;
FullRgn, ClientRgn, CtlRgn : THandle;
procedure TForm1.DoInvisible;
var
AControl : TControl;
A, Margin, X, Y, CtlX, CtlY : Integer;
begin
Margin := ( Width - ClientWidth ) div 2;
//Pegamos a região do form
FullRgn := CreateRectRgn(0, 0, Width, Height);
//Procuramos a área Client
X := Margin;
Y := Height - ClientHeight - Margin;
ClientRgn := CreateRectRgn( X, Y, X + ClientWidth, Y + ClientHeight );
CombineRgn( FullRgn, FullRgn, ClientRgn, RGN_DIFF );
//Agora procuramos nossos controles no form
for A := 0 to ControlCount - 1 do begin
AControl := Controls[A];
if ( AControl is TWinControl ) or ( AControl is TGraphicControl )
then with AControl do begin
if Visible then begin
CtlX := X + Left;
CtlY := Y + Top;
CtlRgn := CreateRectRgn( CtlX, CtlY, CtlX + Width, CtlY + Height );
CombineRgn( FullRgn, FullRgn, CtlRgn, RGN_OR );
end;
end;
end;
//Depois de todas as regiões registradas, executamos o efeito
SetWindowRgn(Handle, FullRgn, TRUE);
end;
Obs.: Primeiro crie a rotina para esconder o form, aproveite e declare as variáveis locais ao form (não a procedure, pois utilizaremos elas em outros procedimentos também).
Apesar de a primeira vista parecer confuso, uma análise mais calma demonstra claramente o passo a passo do código, Aonde procuramos delimitar as regiões do form, sua área total, sua área cliente e a área preenchida com seus controles.
Como todo veneno tem seu antídoto, vamos agora desfazer, torna-lo visível:
procedure TForm1.DoVisible;
begin
// devolve a visibilidade para a região
FullRgn := CreateRectRgn(0, 0, Width, Height);
CombineRgn(FullRgn, FullRgn, FullRgn, RGN_COPY);
SetWindowRgn(Handle, FullRgn, TRUE);
end;
Bem mais simples, né? Talvez. Na verdade precisamos entender o vilão dos dois procedimentos, a função API CombineRgn e seus parâmetros.
A função CombineRgn, combina duas regiões e retorna seu valor numa terceira região. Veja a sintaxe:
Int CombineRgn(
HRGN hrgnDest, // handle to destination region
HRGN hrgnSrc1, // handle to source region
HRGN hrgnSrc2, // handle to source
region
int fnCombineMode // region combining
mode
);
Os três primeiros parâmetros são intuitivos, o macete está no quarto parâmetro, que possui uma lista de opções e responsável diretamente pelo efeito desejado, veja algumas destas opções abaixo:
- RGN_AND: Cria a interseção das duas regiões combinadas.
- RGN_COPY: Cria uma cópia da região identificada por hrgnSrc1.
- RGN_DIFF: Combina as partes de hrgnSrc1 sem a parte de hrgnSrc2.
- RGN_OR: Cria a união de duas regiões combinadas.
- RGN_XOR: Cria a união de duas regiões combinadas com exceção de qualquer área sobrepondo-a.
Revelamos o motivo da mágica, as demais APIs utilizadas podem ter uma explicação mais breve:
- CreateRectRgn: Cria uma região retangular.
- SetWindowRgn: Desenha, aplica uma região em uma janela.
Aproveitarei para fazer meu comercial. Precisando de maiores explicações sobre estas ou outras APIs, basta mandar um email para: Visual Books Editora e encomendar meu novo livro, entitulado "Delphi, API's e Sockets - A caixa preta das tecnologias".
Voltando ao nosso problema, ainda não terminamos, precisamos criar um botão para mostrar e esconder o form. Ao finalizar nosso aplicativo, devemos destruir as regiões criadas (que são consideradas objetos).
procedure TForm1.FormDestroy(Sender: TObject);
begin
DeleteObject(ClientRgn);
DeleteObject(FullRgn);
DeleteObject(CtlRgn);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if Button1.Caption = 'Mostra Form' then begin
DoVisible;
Button1.Caption := 'Esconde Form';
end
else begin
DoInvisible;
Button1.Caption := 'Mostra Form';
end;
end;
Para finalizar nosso projeto com qualidade, inclua também um procedimento para o evento FormResize:
procedure TForm1.FormResize(Sender: TObject);
begin
if Button1.Caption = 'Mostra Form' then
DoInvisible
else
DoVisible;
end;
Vamos agora testar sua lógica de programador: Porque o primeiro código (...Brush.Style := bsClear;) não atualiza a área invisível de nosso form quando ele é movido? A resposta é: Window Region!!!
Vou te contar uma coisa impressionante, quando o a área Client do form está invisível, e você tentar clicar nela com o mouse, ela simplesmente não existe e o foco passa para o aplicativo que esta por baixo, ou seja, ela esta invisível aos olhos e ao toque - Gostei!
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo