Você está na página 1de 14

Dicas de Delphi - Formulários

 Forçar foco em janela


 Anexar dois forms
 Impedir que o form seja fechado com Alt+F4
 Impedir que o form seja arrastado para fora das margens da tela
 Enviar comandos de rolagem vertical para um TMemo
 Construir a barra de título do form com um Panel
 Criar form sem título que possa ser arrastado
 Criar caixas de diálogo em tempo de execução
 Determinar se uma janela (form) está maximizada
 Determinar se o aplicativo está minimizado
 Maximizar um form de forma que cubra toda a tela, inclusive a barra de tarefas
 Posicionar Form's em relação ao Desktop do Windows
 Salvar/restaurar o tamanho e posição de Form's
 Mostrar um Form de LogOn antes do Form principal
 Fazer a barra de título ficar intermitente (piscante)

Forçar foco em janela

As funções abaixo forçam para que a janela informada fique em primeiro plano.

Primeira alternativa
function ForceForegroundWindow(hwnd: THandle): Boolean;
const
SPI_GETFOREGROUNDLOCKTIMEOUT = $2000;
SPI_SETFOREGROUNDLOCKTIMEOUT = $2001;
var
ForegroundThreadID: DWORD;
ThisThreadID: DWORD;
timeout: DWORD;
begin
if IsIconic(hwnd) then ShowWindow(hwnd, SW_RESTORE);

if GetForegroundWindow = hwnd then Result := True


else
begin
// Windows 98/2000 doesn't want to foreground a window when some
other
// window has keyboard focus

if ((Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion


> 4)) or
((Win32Platform = VER_PLATFORM_WIN32_WINDOWS) and
((Win32MajorVersion > 4) or ((Win32MajorVersion = 4) and
(Win32MinorVersion > 0)))) then
begin
// Code from Karl E. Peterson, www.mvps.org/vb/sample.htm
// Converted to Delphi by Ray Lischner
// Published in The Delphi Magazine 55, page 16
Result := False;
ForegroundThreadID :=
GetWindowThreadProcessID(GetForegroundWindow, nil);
ThisThreadID := GetWindowThreadPRocessId(hwnd, nil);
if AttachThreadInput(ThisThreadID, ForegroundThreadID, True)
then
begin
BringWindowToTop(hwnd); // IE 5.5 related hack
SetForegroundWindow(hwnd);
AttachThreadInput(ThisThreadID, ForegroundThreadID, False);
Result := (GetForegroundWindow = hwnd);
end;
if not Result then
begin
// Code by Daniel P. Stasinski
SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0,
@timeout, 0);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0,
TObject(0),
SPIF_SENDCHANGE);
BringWindowToTop(hwnd); // IE 5.5 related hack
SetForegroundWindow(hWnd);
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0,
TObject(timeout), SPIF_SENDCHANGE);
end;
end
else
begin
BringWindowToTop(hwnd); // IE 5.5 related hack
SetForegroundWindow(hwnd);
end;

Result := (GetForegroundWindow = hwnd);


end;
end; { ForceForegroundWindow }

Segunda alternativa

A função abaixo consegue forçar o foco na janela especificada criando-se um


formulário com dimensão de um apenas 1 ponto e simulando um clique de mouse neste
formulário para que a aplicação receba o foco de entrada. Em seguida a janela
especificada é colocada em primeiro plano usando-se a função SetForegroundWindow
da API do Windows.
procedure ForceForegroundWindow(hwnd: THandle);
// (W) 2001 Daniel Rolf
// http://www.finecode.de
// rolf@finecode.de
var
hlp: TForm;
begin
hlp := TForm.Create(nil);
try
hlp.BorderStyle := bsNone;
hlp.SetBounds(0, 0, 1, 1);
hlp.FormStyle := fsStayOnTop;
hlp.Show;
mouse_event(MOUSEEVENTF_ABSOLUTE or MOUSEEVENTF_LEFTDOWN, 0, 0, 0,
0);
mouse_event(MOUSEEVENTF_ABSOLUTE or MOUSEEVENTF_LEFTUP, 0, 0, 0,
0);
SetForegroundWindow(hwnd);
finally
hlp.Free;
end;
end;

Terceira alternativa

A biblioteca USER32.DLL possui uma função não documentada que propõe forçar o
foco em determinada janela. A declaração da função é:
procedure SwitchToThisWindow(h1: hWnd; x: bool); stdcall;
external user32 Name 'SwitchToThisWindow';
{x = false: Size unchanged, x = true: normal size}

{ Exemplo }

procedure TForm1.Button2Click(Sender: TObject);


begin
SwitchToThisWindow(FindWindow('notepad', nil), True);
end;

Atenção!

Nos testes que fiz usando Windows XP Professional e Delphi 6, a primeira e segunda
alternativas funcionaram perfeitamente. A última não funcionou nos testes, mas foi
mantida aqui para que outras pessoas possam experimentá-la.

Autor: Desconhecido

Início

Anexar dois forms


É comum encontrarmos aplicativos que possuem dois ou mais
formulários que se mantém o tempo todo "colados" um ao outro.
É o caso, por exemplo, do conhecido Winamp. Como fazer isto
em aplicações Delphi? Vamos aos passos:

1. Crie um novo projeto com um form (Form1).


2. Adicione mais um form (Form2).
3. Declare os métodos abaixo na seção private do Form1:

private
procedure AjustarForm2;
procedure WMMove(var Msg: TMessage); message WM_MOVE;

4. Abaixo da palavra implementation escreva:

procedure TForm1.AjustarForm2;
begin
if Form2 <> nil then begin
Form2.Width := Width;
Form2.Left := Left;
Form2.Top := Top + Height;
end;
end;

procedure TForm1.WMMove(var Msg: TMessage);


begin
AjustarForm2;
end;

5. Escreva o evento OnShow do Form1 como abaixo:

procedure TForm1.FormShow(Sender: TObject);


begin
Form2.Show;
end;

6. Escreve o evento OnHide do Form1 como abaixo:

procedure TForm1.FormHide(Sender: TObject);


begin
Form2.Hide;
end;

7. Escreve o evento OnReSize do Form1 como abaixo:

procedure TForm1.FormResize(Sender: TObject);


begin
AjustarForm2;
end;

Pronto! Execute e experimente arrastar ou redimensionar o


Form1 para ver o efeito.

Observações

Neste exemplo, se o usuário mexer no Form2 o Form1 não se ajustará automaticamente.


Existem no mínimo duas alternativas para resolver este caso: deixar o Form2 sem borda
ou codificar os eventos do Form2 para ajustar o Form1.

Autor: Daniel P. Guimarães


Home-page: www.tecnobyte.com.br

Início

Impedir que o form seja fechado com Alt+F4


Este é um problema fácil de resolver. Vejamos porque.

Toda vez que um form recebe um comando para ser fechado,


tal como Form1.Close ou mesmo uma mensagem WM_CLOSE, o evento
OnCloseQuery é disparado. Este evento passa um parâmetro por
referência normalmente chamado CanClose. Se alternarmos o valor
deste parâmetro para false o processo de fechar o formulário
será cancelado.

Uma vez que queremos impedir que o form seja fechado com
Alt+F4, temos que dar ao usuário outra forma de fechá-lo.
Neste exemplo vamos colocar um botão para esta tarefa.

Vamos aos passos:

1. Declare um campo (variável) na seção private do Form:

private
FPodeFechar: boolean;

2. No evento OnCreate do form coloque:

FPodeFechar := false;

3. No evento OnCloseQuery do form coloque:

CanClose := FPodeFechar;

4. Coloque um botão no form e no seu evento Click coloque:

FPodeFechar := true;
Close;

Pronto! Execute e teste.

Autor: Daniel P. Guimarães


Home-page: www.tecnobyte.com.br

Início

Impedir que o form seja arrastado para fora das margens da tela
- Na seção Private declare a procedure abaixo:

private
procedure WMMove(var Msg: TWMMove); message WM_MOVE;

- Abaixo da palavra implementation escreva a procedure


abaixo:

procedure TForm1.WMMove(var Msg: TWMMove);


begin
if Left < 0 then
Left := 0;
if Top < 0 then
Top := 0;
if Screen.Width - (Left + Width) < 0 then
Left := Screen.Width - Width;
if Screen.Height - (Top + Height) < 0 then
Top := Screen.Height - Height;
end;

Para testar:

- Execute o programa e tente arrastar o form para fora


das margens da tela e veja o que acontece.
Autor: Daniel P. Guimarães
Home-page: www.tecnobyte.com.br

Início

Enviar comandos de rolagem vertical para um TMemo

Inclua na seção uses: Windows


Problema:

Gostaria que o meu programa rolasse automaticamente o


conteúdo de um TMemo, simulando o deslizamento da barra de
rolagem vertical. Isto é possível no Delphi?

Solução:

Sim. Utilizando mensagens do Windows isto é fácil. Vejamos


algums exemplos:

SendMessage(Memo1.Handle, WM_VSCROLL, SBPAGEDOWN, 0);

Onde:
Memo1.Handle = manipulador da janela do Memo1.
WM_VSCROLL = Mensagem do Windows - rolagem vertical.
SB_PAGEDOWN = Comanndo de rolagem - página para baixo.

Outros exemplos:

{ Página para cima }


SendMessage(Memo1.Handle, WM_VSCROLL, SBPAGEUP, 0);

{ Linha para baixo }


SendMessage(Memo1.Handle, WM_VSCROLL, SBLINEDOWN, 0);

{ Linha para cima }


SendMessage(Memo1.Handle, WM_VSCROLL, SBLINEUP, 0);

Observações

Além desta técnica existem API's do Windows que fazem um trabalho equivalente.

Autor: Daniel P. Guimarães


Home-page: www.tecnobyte.com.br

Início

Construir a barra de título do form com um Panel


Pegue o arquivo tbtitle.zip na seção Download de www.tecnobyte.com.br
Autor: Daniel P. Guimarães
Home-page: www.tecnobyte.com.br

Início

Criar form sem título que possa ser arrastado


Problema:

Fazer um relógio num form é fácil. Porém gostaria que esse


form não possuísse a barra de título, mas que o usuário
ainda pudesse arrastá-lo com o mouse. Isto é possível
no Delphi?

Solução:

Sim, é possível e é fácil. Siga os passos abaixo:

- Crie um novo projeto;


- Mude as seguintes propriedades do Form1:
BorderStyle = bsNone, FormStyle = fsStayOnTop,
- Coloque um Label;
- Coloque um Timer;
- Altere o evento OnTimer do Timer1 conforme abaixo:

procedure TForm1.Timer1Timer(Sender: TObject);


begin
Label1.Caption := TimeToStr(Time);
end;

- Altere o evento OnCreate do Form1 conforme abaixo:

procedure TForm1.FormCreate(Sender: TObject);


begin
Width := 80;
Height := 40;
Label1.Left := 10;
Label1.Top := 10;
end;

- Vá na seção private do Form1 e declare a procedure abaixo:

private
procedure WMNCHitTest(var Msg: TMessage);
message WM_NCHitTest;
public
{ Public declarations }
end;

- Vá na seção implementation e escreva a procedure abaixo:

implementation

{$R *.DFM}

procedure TForm1.WMNCHitTest(var Msg: TMessage);


begin
if GetAsyncKeyState(VK_LBUTTON) < 0 then
Msg.Result := HTCAPTION
else
Msg.Result := HTCLIENT;
end;

- Execute e experimente arrastar form com o mouse.

Observações

Para fechar este aplicativo pressione Alt+F4. Uma alternativa mais elegante é colocar
um menu local (PopupMenu) com um comando para fechar.

Autor: Daniel P. Guimarães


Home-page: www.tecnobyte.com.br

Início

Criar caixas de diálogo em tempo de execução

Inclua na seção uses: Forms, StdCtrls, Buttons


A função abaixo demonstra a criação de uma caixa de diálogo
que pode ser usada para permitir ao usuário digitar o seu
nome:

{ Esta função retorna true se for pressionado OK e false


em caso contrário. Se for OK, o texto digitado pelo usuário
será copiado para a variável Nome }

function ObterNome(var Nome: string): boolean;


var
Form: TForm; { Variável para o Form }
Edt: TEdit; { Variável para o Edit }
begin
Result := false; { Por padrão retorna false }
{ Cria o form }
Form := TForm.Create(Application);
try
{ Altera algumas propriedades do Form }
Form.BorderStyle := bsDialog;
Form.Caption := 'Atenção';
Form.Position := poScreenCenter;
Form.Width := 200;
Form.Height := 150;
{ Coloca um Label }
with TLabel.Create(Form) do begin
Parent := Form;
Caption := 'Digite seu nome:';
Left := 10;
Top := 10;
end;
{ Coloca o Edit }
Edt := TEdit.Create(Form);
with Edt do begin
Parent := Form;
Left := 10;
Top := 25;
{ Ajusta o comprimento do Edit de acordo com a largura
do form }
Width := Form.ClientWidth - 20;
end;
{ Coloca o botão OK }
with TBitBtn.Create(Form) do begin
Parent := Form;
{ Posiciona de acordo com a largura do form }
Left := Form.ClientWidth - (Width * 2) - 20;
Top := 80;
Kind := bkOK; { Botão Ok }
end;
{ Coloca o botão Cancel }
with TBitBtn.Create(Form) do begin
Parent := Form;
Left := Form.ClientWidth - Width - 10;
Top := 80;
Kind := bkCancel; { Botão Cancel }
end;
{ Exibe o form e aguarda a ação do usuário. Se for OK... }
if Form.ShowModal = mrOK then begin
Nome := Edt.Text;
Result := true;
end;
finally
Form.Free;
end;
end;

Para chamar esta função siga o exemplo abaixo:

procedure TForm1.Button1Click(Sender: TObject);


var
S: string;
begin
if ObterNome(S) then
Edit1.Text := S;
end;

Observações

Os componentes Label, Edit (var Edt) e BitBtn's (botões) não são destruídos
explicitamente (Componente.Free). Isto não é necessário, pois ao criá-los informei
como proprietário o Form (ex: TLabel.Create(Form)). Neste caso, estes componentes
são destruídos automaticamente ao destruir o Form (Form.Free).

Autor: Daniel P. Guimarães


Home-page: www.tecnobyte.com.br

Início

Determinar se uma janela (form) está maximizada

Inclua na seção uses: Windows


if IsZoomed(Form1.Handle) then
{ Form1 está maximizado }
else
{ Form2 NÃO está maximizado }

Autor: Daniel P. Guimarães


Home-page: www.tecnobyte.com.br

Início

Determinar se o aplicativo está minimizado

Inclua na seção uses: Windows


if IsIconic(Application.Handle) then
{ Minimizado }
else
{ Não minimizado }

Observações

Pode-se verificar qualquer janela (form). Só um lembrete: quando clicamos no botão de


minimizar do form principal, na verdade ele é oculto e o Application é que é minizado.

Autor: Daniel P. Guimarães


Home-page: www.tecnobyte.com.br

Início

Maximizar um form de forma que cubra toda a tela, inclusive a barra de


tarefas
{ É um "maximizar" com jeitinho brasileiro... mas funciona.
No evento OnShow do form coloque o código abaixo: }

Top := 0;
Left := 0;
Width := Screen.Width;
Height := Screen.Height;

Observações

Nos testes que fiz, mesmo com a barra de tarefas marcada como "Sempre Visível",
funcionou perfeitamente. Fiz os testes usando o Win95. Talvez em novas versões, possa
apresentar problemas.

Autor: Daniel P. Guimarães


Home-page: www.tecnobyte.com.br
Início

Posicionar Form's em relação ao Desktop do Windows


{ Quando usamos a propridade Position de um Form para
centralizá-lo estamos sujeitos a um inconveniente:
dependendo da posição/tamanho da barra de tarefas do
Windows, o nosso Form poderá ficar parcialmente coberto
por ela. Uma forma eficaz de resolver este problema é
posicionar o form considerando apenas a área livre do
Desktop. Vejamos este exemplo:

- Crie um novo projeto;


- Na seção implementation digite a procedure abaixo:
}

procedure FormPos(Form: TForm; const Horz, Vert: byte);


{ Horz: 1=esquerda, 2=centro, 3=direita
Vert: 1=topo, 2=centro, 3=em baixo }
var
R: TRect;
begin
if not SystemParametersInfo(SPI_GETWORKAREA, 0, @R, 0) then
R := Rect(0, 0, Screen.Width, Screen.Height);
with Form do
case Horz of
1: Form.Left := 0;
2: Form.Left := (R.Right - R.Left - Width) div 2;
3: Form.Left := R.Right - Width;
end;
with Form do
case Vert of
1: Form.Top := 0;
2: Form.Top := (R.Bottom - R.Top - Height) div 2;
3: Form.Top := R.Bottom - Height;
end;
end;

{ - Coloque dois TEdit's: Edit1 e Edit2;


- Coloque um TButton e altere o evento OnClick deste
conforme abaixo:
}

procedure TForm1.Button1Click(Sender: TObject);


begin
FormPos(Form1, StrToInt(Edit1.Text), StrToInt(Edit2.Text));
end;

Observações

Para testar, execute este exemplo e experimente digitar números de 1 a 3 em ambos os


Edit's e clique no Button para ver o resultado. O Edit1 indica a posição horizontal
(esquerda, centro e direita) e o Edit2 indica a posição vertical (topo, centro e em baixo).

Autor: Daniel P. Guimarães


Home-page: www.tecnobyte.com.br
Início

Salvar/restaurar o tamanho e posição de Form's


{ Crie uma nova Unit conforme abaixo: }
unit uFormFunc;

interface
uses Forms, IniFiles, SysUtils, Messages, Windows;

procedure tbLoadFormStatus(Form: TForm; const Section: string);


procedure tbSaveFormStatus(Form: TForm; const Section: string);

implementation

procedure tbSaveFormStatus(Form: TForm; const Section: string);


var
Ini: TIniFile;
Maximized: boolean;
begin
Ini := TIniFile.Create(ChangeFileExt(
ExtractFileName(ParamStr(0)),'.INI'));
try
Maximized := Form.WindowState = wsMaximized;
Ini.WriteBool(Section, 'Maximized', Maximized);
if not Maximized then begin
Ini.WriteInteger(Section, 'Left', Form.Left);
Ini.WriteInteger(Section, 'Top', Form.Top);
Ini.WriteInteger(Section, 'Width', Form.Width);
Ini.WriteInteger(Section, 'Height', Form.Height);
end;
finally
Ini.Free;
end;
end;

procedure tbLoadFormStatus(Form: TForm; const Section: string);


var
Ini: TIniFile;
Maximized: boolean;
begin
Maximized := false; { Evita msg do compilador }
Ini := TIniFile.Create(ChangeFileExt(
ExtractFileName(ParamStr(0)),'.INI'));
try
Maximized := Ini.ReadBool(Section, 'Maximized', Maximized);
Form.Left := Ini.ReadInteger(Section, 'Left', Form.Left);
Form.Top := Ini.ReadInteger(Section, 'Top', Form.Top);
Form.Width := Ini.ReadInteger(Section, 'Width', Form.Width);
Form.Height := Ini.ReadInteger(Section, 'Height', Form.Height);
if Maximized then
Form.Perform(WM_SIZE, SIZE_MAXIMIZED, 0);
{ A propriedade WindowState apresenta Bug.
Por isto usei a mensagem WM_SIZE }
finally
Ini.Free;
end;
end;
end.

{
Em cada formulário que deseja salvar/restaurar:
- Inclua na seção uses: uFormFunc
- No evento OnShow digite:
tbLoadFormStatus(Self, Self.Name);
- No evento OnClose digite:
tbSaveFormStatus(Self, Self.Name);
}

Observações

O arquivo INI terá o nome do executável e extensão INI e será salvo no diretório do
Windows. A palavra Self indica o Form relacionado com a unit em questão. Poderia ser,
por exemplo, Form1, Form2, etc. Onde aparece Self.Name poderá ser colocado um
nome a sua escolha. Este nome será usado como SectionName no arquivo INI e deve ser
idêntico no evento OnShow e OnClose de um mesmo Form, porém para cada Form
deverá ser usado um nome diferente.

Autor: Daniel P. Guimarães


Home-page: www.tecnobyte.com.br

Início

Mostrar um Form de LogOn antes do Form principal


{
* Crie um novo Projeto. Este certamente terá o Form1.
* Adicione um novo Form (Form2).
* Coloque no Form2 dois botões TBitBtn.
* Mude a propriedade Kind do BitBtn1 para bkOK.
* Mude a propriedade Kind do BitBtn2 para bkCancel.
* Vá no menu "Project/Options" na aba "Forms" e passe o
Form2 de "Auto-create Forms" para "Available Forms".
* Abra o arquivo Project.dpr (menu Project/View Source).
* Altere o conteúdo deste arquivo conforme abaixo:
}

program Project1;

uses
Forms, Controls,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2};

{$R *.RES}

var
F: TForm2;

begin
F := TForm2.Create(Application);
try
if F.ShowModal = mrOK then begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end;
finally
F.Free;
end;
end.

Observações

O Form2 do exemplo é o Form de LogOn. Este deverá ser preparado para que se possa
escolher o usuário, digitar a senha, etc.

Autor: Daniel P. Guimarães


Home-page: www.tecnobyte.com.br

Início

Fazer a barra de título ficar intermitente (piscante)

Inclua na seção uses: Windows


{ Coloque um TTimer no Form desejado. Define a propriedade
Interval do Timer para 1000 (1 segundo). Modifique
o evento OnTimer do Timer conforme abaixo: }

procedure TForm1.Timer1Timer(Sender: TObject);


begin
FlashWindow(Handle, true);
FlashWindow(Application.Handle, true);
end;

Autor: Daniel P. Guimarães


Home-page: www.tecnobyte.com.br

Início

Página atualizada em 01 de maio de 2007


Todos os direitos reservados
www.tecnobyte.com.br

Você também pode gostar