Super Dicas Delphi parte IX

 


Reduzindo o tempo de carga de um programa Delphi

É comum acontecer um sensível aumento do tempo de carga de um aplicativo desenvolvido em Delphi à medida que este aplicativo cresce e adquire mais e mais formulários. Às vezes o tempo de carga se torna totalmente insuportável. 
Os programas se tornam lentos principalmente devido à grande quantidade de formulários que são criados e inicializados logo no início da execução do programa. Antes de ser efetivamente utilizado, todo formulário precisa ser criado. A criação do formulário também provoca a criação de todos os componentes incluidos nele. Além disto, o código que o programador escreveu para o evento FormCreate é executado. 
Sempre que você adiciona um novo formulário ao sistema, o IDE do Delphi providencia código para que ele seja criado automaticamente. Isto simplifica a vida do programador que não precisará se preocupar com este detalhe. 
O aumento do tempo de carga do aplicativo pode ser resolvido pela simples remoção do código que o Delphi gerou para a criação do formulário. Entretanto isto cria um problema. Antes de efetivamente mostrar o formulário na tela (ou antes de usar e/ou alterar qualquer componente contido nele), nós deveremos incluir manualmente o código para criá-lo. 
Para remover o código que o Delphi criou automaticamente, selecione Project|Options no menu. Selecione a aba 'Forms'. Aponte para um dos formulários e clique no botão '>'. Isto faz com que o formulário passe do painel 'Auto-create forms' para o painel 'Available forms'. Isto também retira o código que o Delphi criou. 
Se você quer saber onde está este código, clique em View|Units (ou use Ctrl-F12) e selecione o seu projeto na lista de units que aparecerá. O código que cria formulários é algo mais ou menos como se segue: 
Application.CreateForm(TForm1, Form1); 
Cada formulário auto-criado terá uma linha como esta. Quando o formulário passa para o painel de 'Available forms', a linha correspondente é removida. Você também pode simplesmente remover a linha manualmente, usando o editor de textos. 
Tipicamente usar um formulário significa mostrá-lo na tela. Isto é feito invocando-se os métodos Show ou ShowModal do formulário conforme o estilo do aplicativo. Agora que o formulário não é mais criado automaticamente, isto se torna um pouco mais complicado. Mostrar o formulário agora requer uma codificação como a que se segue: 
if Form1 = nil then 
Form1 := TForm1.Create ( Application ); 
Form1.Show; { ou Form1.ShowModal; } 
Alternativamente você poderia escrever assim: 
if Form1 = nil then 
Application.CreateForm ( TForm1, Form1 ); 
Form1.Show; { ou Form1.ShowModal; } 
O efeito é o mesmo, mas eu, pessoalmente, prefiro a primeira forma. 
Você deve ter extremo cuidado ao usar esta técnica. Se você tirar o código de criação automática do formulário e tentar executar o Show ou ShowModal você vai receber um erro do tipo 'Access violation'. Tome cuidado e faça isto um formulário por vez. 
Atenção! Não faça isto para o seu formulário principal. O formulário principal precisa ser o primeiro formulário a ser criado. Assim é melhor mantê-lo como auto-criado. 
Esta técnica efetivamente 'distribui' o tempo de carga e inicialização do aplicativo pela execução do programa. Os formulários agora são carregados 'sob-demanda'. Formulários nunca utilizados nunca serão criados. Isto também melhora o uso de memória e é benéfico ao seu computador (e à sua rede, eventualmente) como um todo. 


Como saber o estado das teclas Num lock, Caps lock e Scroll lock 

Para saber o estado das teclas acima citadas, utilize a função getkeystate em conjunto com o código das teclas, ela retorna 0 se a tecla estiver OFF e 1 se a tecla estiver ON, assim: 
If getkeystate(vk_numlock) = 0 then // Num lock está OFF 
If getkeystate(vk_numlock) = 1 then // Num lock está ON 
If getkeystate(vk_scroll) = 0 then // Scroll lock está OFF 
If getkeystate(vk_scroll) = 1 then // Scroll lock está ON 
If getkeystate(vk_CAPITAL) = 0 then // Caps lock está OFF 
If getkeystate(vk_CAPITAL) = 1 then // Caps lock está ON 


Como extrair o ícone de um executável 

Inclua a unit Shellapi na cláusula uses do seu form. 
Image1.Picture.Icon.Handle:= ExtractIcon(Handle,PChar('c:\windows\calc.exe'),0); 


Como criar um alias dinamicamente na memória

procedure TForm1.FormCreate(Sender: TObject);
begin
if not Session.IsAlias('Teste') then
session.AddStandardAlias('Teste',
ExtractFilePath(Application.ExeName),'PARADOX');
end;


Desabilitando um RadioButton num RadioGroup 

TRadioButton(RadioGroup1.Controls[1]).
Enabled := False; 


Ativar a proteção de tela do Windows Inclua na seção uses: Windows

{ Ativa a proteção de tela do Windows, se estiver configurada. }

SendMessage(Application.Handle, WM_SYSCOMMAND, SC_SCREENSAVE, 0);


Desligar/Ligar monitor

Inclua na seção uses: Windows

No Win95 podemos desligar o monitor afim de economizar energia elétrica. Normalmente este recurso é controlado pelo próprio Windows. Porém sua aplicação Delphi também pode fazer isto. O exemplo abaixo desliga o monitor, aguarde 5 segundos e re-liga monitor.

SendMessage(Application.Handle, WM_SYSCOMMAND, 
SC_MONITORPOWER, 0);
Sleep(5000); { Aguarde 5 segundos }
SendMessage(Application.Handle, WM_SYSCOMMAND, 
SC_MONITORPOWER, -1);

Observações

Este recurso pode não funcionar dependendo da configuração do sistema


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.


Criar sub-diretório no diretório do EXE

Inclua na seção uses: FileCtrl, SysUtils

function CriaSubDir(const NomeSubDir: string): boolean;
var
Caminho: string;
begin
Caminho := ExtractFilePath(ParamStr(0)) + NomeSubDir;
if DirectoryExists(Caminho) then
Result := true
else
Result := CreateDir(Caminho);
end;


Exemplo de uso:
- Chame a função no evento OnCreate do form:

procedure TForm1.FormCreate(Sender: TObject);
begin
if not CriaSubDir('MeuSubDir') then
ShowMessage('Não foi possível criar o sub-diretório MeuSubDir.');
end;


Mudar a cor de um DBEdit dentro de um DBCtrlGrid de acordo com uma condição 

- Monte o form normalmente colocando DataSource, Table, DBCtrlGrid e os DBEdit's, DBText's, etc.

- Escreva no manipulador do evento OnPaintPanel do DBCtrlGrid conforme abaixo:

procedure TForm1.DBCtrlGrid1PaintPanel(DBCtrlGrid: TDBCtrlGrid;
Index: Integer);
begin
if Table.FieldByName('NomeDoCampo').AsFloat < 0 then
DBEdit1.Font.Color := clRed
else
DBEdit1.Font.Color := clBlue;
end;

Observações

Neste exemplo mudamos a cor da fonte do componente DBEdit, Porém, pode-se também mudar a cor do próprio componente (DBEdit1.Color). 


Configurar linhas de diferentes alturas em StringGrid 

- Coloque o StringGrid no form.
- No evento OnCreate do form coloque o código abaixo:

procedure TForm1.FormCreate(Sender: TObject);
begin
StringGrid1.RowHeights[0] := 15;
StringGrid1.RowHeights[1] := 20;
StringGrid1.RowHeights[2] := 50;
StringGrid1.RowHeights[3] := 35;
end;

Observações

Cuidado para não especificar uma linha inexistente. 


Adicionar o evento OnClick do DBGrid 

- Monte seu form normalmente, colocando o DBGrid e demais componentes;
- Vá na seção "private" da unit e declare a procedure abaixo:

private
procedure DBGridClick(Sender: TObject);

- Logo após a palavra "implementation", escreva a procedure:

implementation

{$R *.DFM}

procedure TForm1.DBGridClick(Sender: TObject);
begin
ShowMessage('Clicou no DBGrid.');
end;

- Coloque as instruções abaixo no evento OnCreate do Form:

procedure TForm1.FormCreate(Sender: TObject);
begin
DBGrid1.ControlStyle :=
DBGrid1.ControlStyle + [csClickEvents];
TForm(DBGrid1).OnClick := DBGridClick;
end;

- E pronto. Execute e teste.

Observações

O segredo principal desta dica está OnCreate do Form. A primeira instrução ativa o evento OnClick. A segunda instrução acessa o manipulador do evento OnClick. Para isto precisamos tratar o DBGrid como se fosse Form, pois o evento OnClick está declarado como protegido (protected) na classe TDBGrid. 


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). 


Mostrar uma mensagem durante um processamento

- Crie um form com a mensagem. Um pequeno form com um Label já é suficiente. Aqui vou chamá-lo de FormMsg.
- Vá em Project|Options e passe o FormMsg de "Auto-create forms" para "Available forms".
- Abaixo vou simular um processamento demorado, usando a API Sleep:

procedure TForm1.Button1Click(Sender: TObject);
var
Form: TFormMsg;
I: integer;
begin
Form := TFormMsg.Create(Self);
try
Form.Label1.Caption := 'Processamento demorado...';
Form.Show;
for I := 1 to 5 do begin
Form.UpDate;
Sleep(1000); { Aguarda um segundo }
end;
finally
Form.Free;
end;
end;

Observações

A função Sleep é uma API do Windows e serve para paralisar a aplicação por um determinado dempo. Este tempo é em milisegundos. 


Obter o endereço IP do Dial-Up

Inclua na seção uses: WinSock

{ Esta função retorna o endereço IP do Dial-Up. }

function GetLocalIP : string;
type
TaPInAddr = array [0..10] of PInAddr;
PaPInAddr = ^TaPInAddr;
var
phe : PHostEnt;
pptr : PaPInAddr;
Buffer : array [0..63] of char;
I : Integer;
GInitData : TWSADATA;
begin
WSAStartup($101, GInitData);
Result := '';
GetHostName(Buffer, SizeOf(Buffer));
phe :=GetHostByName(buffer);
if phe = nil then Exit;
pptr := PaPInAddr(Phe^.h_addr_list);
I := 0;
while pptr^[I] <> nil do begin
result:=StrPas(inet_ntoa(pptr^[I]^));
result := StrPas(inet_ntoa(pptr^[I]^));
Inc(I);
end;
WSACleanup;
end;

Observações

Se o endereço IP for designado pelo servidor, a cada conecção teremos um endereço IP diferente e, obviamente, se não estivermos conectados, não conseguiremos obtê-lo.


 

1