31 de jan. de 2005

Como evitar que a barra de tarefas oculte parte do form maximizado?

Do fórum ClubeDelphi:

Quando deixo o meu form principal com a propriedade WindowState com o valor wsMaximized, a parte inferior do form fica oculta pela barra de tarefas. O form não respeita o espaço livre da tela.

Como o problema não pode ser reproduzido, ao longo da discussão apareceu o causador do problema:

S[e] não me engano vc não pode desabilitar os botões de maximizar do form principal. Tenta lá... na opção BorderIcons deixa True para biMaximize.

Puxa... não ter o botão Maximizar e iniciar com o form maximizado causa o problema... Testei o tratamento da mensagem WM_GETMINMAXINFO e isso resolve o problema:

1 type 2 TSeuForm = class(... 3 private 4 procedure WMGetMinmaxInfo(var Msg: TWMGetMinmaxInfo); message WM_GETMINMAXINFO; 5 ... 6 7 procedure TSeuForm.WMGetMinmaxInfo(var Msg: TWMGetMinmaxInfo); 8 var 9 R: TRect; 10 begin 11 inherited; 12 13 // Obtem o retangulo com a area livre do desktop 14 SystemParametersInfo(SPI_GETWORKAREA, SizeOf(R), @R, 0); 15 16 Msg.MinMaxInfo^.ptMaxPosition := R.TopLeft; 17 OffsetRect(R, -R.Left, -R.Top); 18 Msg.MinMaxInfo^.ptMaxSize := R.BottomRight; 19 end;

Qual é o tamanho da barra de tarefas?

Do fórum ClubeDelphi:

Como conseguir a altura e a posição da barra de tarefas?

O código seguinte obtem o retângulo que contem a barra de tarefas do Windows:

1 var 2 TaskBarH: THandle; 3 TaskBarR: TRect; 4 ... 5 // obtem o retangulo com o taskbar 6 TaskBarH := FindWindow('Shell_TrayWnd', nil); 7 GetWindowRect(TaskBarH, TaskBarR); 8 9 // altura do taskbar = TaskBarR.Bottom - TaskBarR.Top

Como fazer alinhamento no DBGrid?

Do fórum ClubeDelphi:

Gostaria de mudar a cor da fonte de um valor negativo no meu DBGrid... a rotina eu já tenho.. só que minha coluna são todas centralizadas e quando coloco minha rotina, o registro que tem valor negativo fica todo desalinhado

Você está usando a procedure TCanvas.TextOut que não alinha texto... use DrawText da API do Windows para alinhar o texto dentro de um retângulo:

1 procedure TForm1.DBGridDrawColumnCell(Sender: TObject; const Rect: TRect; 2 DataCol: Integer; Column: TColumn; State: TGridDrawState); 3 var 4 S: string; 5 R: TRect; 6 begin 7 if Column.Field.AsDouble < 0 then begin 8 9 with DBGrid.Canvas do begin 10 11 Font.Color := clRed; 12 FillRect(Rect); 13 S := Column.Field.AsString; 14 R := Rect; 15 DrawText(Handle, PChar(S), Length(S), R, DT_CENTER or DT_VCENTER); 16 end; 17 end; 18 end;

No mesmo evento OnDrawColumnCell, você pode tratar individualmente cada coluna conforme o valor de DataCol ou de Column.

Para ter diferentes alinhamentos, basta mudar o último parametro de DrawText conforme sua necessidade; DrawText alinha tanto na horizontal (esquerda, centro, direita) como na vertical (topo, centro, fundo) além de fazer algumas outras mágicas... veja mais detalhes neste artigo no MSDN.

Como clonar um objeto?

Do fórum ClubeDelphi:

Como faço para clonar um objeto?

Você pode incluir seu próprio método de clonagem na sua classe:

1 type 2 TEstado = class 3 valor1: byte; 4 valor2: byte; 5 public 6 function Clone: TEstado; 7 end; 8 9 ... 10 11 function TEstado.Clone: TEstado; 12 begin 13 Result := TEstado.Create; 14 Result.valor1 := Self.valor1; 15 Result.valor2 := Self.valor2; 16 end;

O esquema usual de clonagem de objetos costuma se basear na idéia usada em TPersistent.Assign. Para um exemplo, dê uma olhada nesta discussão no NG da Borland.

Quais são as unidades de disco rígido da máquina?

Do fórum ClubeDelphi:

Como faço para saber quais são todas as unidades de disco rígido da máquina que o aplicativo está sendo executado?

Basta combinar as funções GetLogicalDrives e GetDriveType da API do Windows:

1 function ListaHDs: string; 2 var 3 Drives: DWord; 4 Mascara: DWord; 5 S: String; 6 I: Integer; 7 begin 8 Result := ''; 9 10 S := 'A:\'; 11 12 Drives := GetLogicalDrives; 13 14 Mascara := 1; 15 for I:= 1 to 32 do begin 16 17 if (Mascara and Drives) <> 0 then begin 18 19 if GetDriveType(PChar(S)) = DRIVE_FIXED then begin 20 21 Result := Result + S[1]; 22 end; 23 end; 24 25 Mascara := Mascara shl 1; 26 Inc(S[1]); 27 end; 28 end;

Se você tiver apenas um HD (normalmente o drive C), ListaHDs retorna 'C'; se você tiver dois HDs (ou duas partições num mesmo HD), retorna 'CD'.

Como ter somente um determinado componente por form?

Do fórum ClubeDelphi:

Como faço para que só possa existir um componente de determinado tipo em cada form?

Imaginando que esteja desenvolvendo um componente, pode-se testar no construtor do componente se o Owner do componente já possui uma instância do componente.

1 constructor TMeuComponente.Create(AOwner: TComponent); 2 var 3 I: Integer; 4 ... 5 begin 6 if AOwner <> nil and then begin 7 8 for I := 0 to AOwner.ComponentCount - 1 do begin 9 10 if AOwner.Components[I] is TMeuComponente then begin 11 12 raise Exception.Create('Só pode ter um TMeuComponente no form'); 13 end; 14 end; 15 end 16 else begin 17 18 raise Exception.Create('Precisa ter um Owner'); 19 end; 20 21 inherited Create(AOwner); 22 23 // resto da sua inicialização 24 ... 25 end;

Esse exemplo assume que não é permitido criar o componente sem ter um Owner válido.

É possível executar TForm.Close no evento TForm.OnShow?

Ao longo de uma discussão no fórum ClubeDelphi sobre como cancelar a exibição de um form no evento OnShow do próprio form, surgiu uma dúvida sobre se era ou não possível executar TForm.Close no evento TForm.OnShow. Para algumas pessoas, ocorre o erro...

Cannot change Visible in OnShow or OnHide

Fiz alguns testes... na verdade, chamar TForm.Close dentro do evento TForm.OnShow dá problema a não ser que você trate o evento TForm.OnClose e defina um valor para Action diferente de caHide (que é o default). Portanto, este código...

1 type 2 TForm1 = class(TForm) 3 procedure FormShow(Sender: TObject); 4 procedure FormClose(Sender: TObject; var Action: TCloseAction); 5 ... 6 end; 7 8 ... 9 10 procedure TForm1.FormShow(Sender: TObject); 11 begin 12 Close; 13 end; 14 15 procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); 16 begin 17 Action := caFree; 18 end;

...funciona sem problemas enquanto este código...

1 type 2 TForm1 = class(TForm) 3 procedure FormShow(Sender: TObject); 4 // ... 5 end; 6 7 ... 8 9 procedure TForm1.FormShow(Sender: TObject); 10 begin 11 Close; 12 end;

... dá problema se o form não for o form principal do programa. Moral da estória: é possível para chamar TForm.Close no evento TForm.OnShow se...

  • no evento TForm.OnClose você atribuir a Action qualquer valor diferente de caHide OU
  • o form for o form principal do programa.

Como usar arquivos de ajuda em formato CHM em aplicativos Delphi?

Do fórum ClubeDelphi:

Gostaria de saber se existe algum forma de abrir um arquivo de ajuda .CHM direto em algum tópico

Usando a API do HtmlHelp:

1 const 2 HelpFile = 'c:\Alguma\Pasta\MeuArquivo.chm'; 3 var 4 H: HWND; 5 begin 6 // abre a ajuda no tópico intro.htm 7 H := HtmlHelp(0, PChar(HelpFile + '::/intro.htm'), HH_DISPLAY_TOPIC, 0);

Links relacionados

Como fazer carga e vínculo dinâmico de DLLs?

Do fórum:

Como faço para verificar em qual Windows a aplicação está rodando, para poder chamar esta função

function RegisterServiceProcess(dwProcessID, dwType: integer):integer; stdcall; external 'KERNEL32.DLL';

pois quando utilizo ela no Windows NT ele diz que não existe esta função na biblioteca.

A variável global Win32Platform declarada na unit SysUtils permite determinar qual a versão do Windows. Neste caso, se Win32Platform <> VER_PLATFORM_WIN32_NT, então pode chamar a função RegisterServiceProcess. Um $IFDEF não serve, porque o teste da versão do Windows precisa ser feito em tempo de execução.

Ao executar o programa aparece essa mensagem:

Não foi possivel localizar o ponto de entrada do procedimento RegisterServiceProcess na biblioteca de vinculo dinâmico 'KERNEL32.DLL'

O teste da versão do Windows é parte da solução. A mensagem de erro aparece por causa da declaração

function RegisterServiceProcess(dwProcessID,
  dwType: integer):integer; stdcall;
  external 'KERNEL32.DLL'; 

Essa declaração cria um link estático entre o programa e a rotina RegisterServiceProcess; isso significa que quando programa o programa é iniciado, o código de inicialização (gerado pelo Delphi) do programa irá tentar localizar essa rotina na DLL (no caso, kernel32.dll) e irá falhar se não encontrar. O que resolve é criar um link dinâmico com a rotina RegisterServiceProcess. Um jeito de fazer isso (não testado) seria:

1 type 2 TRegisterServiceProcessProc = function (dwProcessID, 3 dwType: integer):integer; stdcall; 4 5 var 6 RegisterServiceProcess: TRegisterServiceProcessProc; 7 H: THandle; 8 begin 9 H := GetModuleHandle('kernel32'); 10 if H <> 0 then begin 11 12 RegisterServiceProcess := GetProcAddress(H, 'RegisterServiceProcess'); 13 if @RegisterServiceProcess <> nil then begin 14 15 RegisterServiceProcess(GetCurrentProcessID, 1); 16 end; 17 end; 18 end;

No exemplo não usei LoadLibrary e nem FreeLibrary porque sei que kernel32.dll é uma DLL que já está carregada pelo programa, por isso uso GetModuleHandle, mas no caso mais geral deveria usar LoadLibrary/FreeLibrary.

Links relacionados

30 de jan. de 2005

Como usar o Mozilla FireFox em aplicativos Delphi?

Do fórum ActiveDelphi:

alguem sabe o nome da classe do Mozila Firefox (ex: a do IE é 'IEFrame' )
Assim como o IE, o Mozilla FireFox é um servidor de automação. O artigo Taming the Lizard with Delphi do site delphi.mozdev.org fala sobre o controle ActiveX Mozilla e faz uma comparação com o TWebBrowser do Internet Explorer.