Dicas de Delphi - Formulários
Forçar foco em janelaAs 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 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 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 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 Enviar comandos de rolagem vertical para um TMemoInclua 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 Construir a barra de título do form com um PanelPegue o arquivo tbtitle.zip na seção Download de www.tecnobyte.com.br Autor: Daniel P. Guimarães 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 Criar caixas de diálogo em tempo de execuçãoInclua 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 Determinar se uma janela (form) está maximizadaInclua na seção uses: Windows
if IsZoomed(Form1.Handle) then
{ Form1 está maximizado }
else
{ Form2 NÃO está maximizado }
Autor: Daniel P. Guimarães Determinar se o aplicativo está minimizadoInclua 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 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 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 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 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 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 Página atualizada em 23 de janeiro de 2012 |