terça-feira, 29 de abril de 2008

Como colocar sua aplicação no Tray?

Olá, caros programadores,

acho que esse post irá ajudar muita gente a resolver um problema em DELPHI que vem atormentando a muita gente. Esse mesmo problema ficou me chateando por um bom tempo, mas no final das contas eu aprendi a lidar com ele e digo: é fácil vencê-lo. Bem, estou inspirado, mas irei direto ao assunto. O que ensinarei a fazer agora, em DELPHI, é como colocar seu programa no Tray (veja este post para saber o que é tray: http://imdm94.blogspot.com/2008/04/o-que-tray.html).
Um exemplo de como fica utilizando os passos que irei informar é visto no programa Despertador desenvolvido por mim e que será postado em breve neste blog. Vamos começar então:

1º passo: declarar na cláusula Uses a Unit ShellApi.

Fica mais ou menos assim:

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Menus, Registry, ShellApi;

2º passo: abaixo da cláusula Uses declarar a constante
const WM_TRAYICON=WM_USER+1;

Assim:

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Menus, Registry, ShellApi;

const WM_TRAYICON=WM_USER+1;

3º passo: na clásula private digite as procedures a seguir:

...
private
{ Private declarations }
{ Tratamento dos Ícones da Aplicação }
procedure WMSysCommand(var Msg: TWMSysCommand); Message WM_SysCommand;
procedure WMTrayIcon(var Msg: TMessage); Message WM_TRAYICON;
procedure DestroyIcone;
procedure CriaIcone;
public
{ Public declarations }
end;

4º passo: Digite a implementação a seguir:

procedure TForm1.CriaIcone;
var
NotifyIconData: TNotifyIconData;
begin
with NotifyIconData do
begin
cbSize:= SizeOf(TNotifyIconData);
Wnd:= Self.Handle;
uID:= 0;
uCallbackMessage:= WM_TRAYICON;
uFlags:= NIF_ICON or NIF_TIP or NIF_MESSAGE;
hIcon:= Application.Icon.Handle;
szTip:= 'Exemplo da utilização do TrayIcon by janbaceiredo';
end;
Shell_NotifyIcon(NIM_ADD, @NotifyIconData);
Application.ShowMainForm:= False;
end;

procedure TForm1.DestroyIcone;
var
NotifyIconData: TNotifyIconData;
begin
NotifyIconData.cbSize:= SizeOf(TNotifyIconData);
NotifyIconData.Wnd:= Self.Handle;
NotifyIconData.uID:= 0;
NotifyIconData.uFlags:= 0;
Shell_NotifyIcon(NIM_DELETE, @NotifyIconData);
end;

{Captura todas as mensagens enviadas para a aplicação.
Neste caso, trabalhamos apenas com as mensagens SC_MINIMIZE e SC_MAXIMIZE, que são enviadas quando devemos Minimizar ou Maximizar o formulario da aplicação. Capturando estas mensagens para esconder o ícone da aplicação da Barra de Tarefas do Windows e para criar / destruir o ícone que ficará ao lado do relógio.

Obs: Você pode trabalhar com outras mensagem também. Tipo SC_CLOSE, SC_RESTORE e etc.}
procedure TForm1.WMSysCommand(var Msg: TWMSysCommand);
begin
case (Msg.CmdType) of
SC_MINIMIZE: {isso daqui faz com que ao você minimizar a tela ele faça com que o programa em vez de ser minimizado normalmente ele irá para o Tray}
begin
Self.Visible:= False;
CriaIcone;
end;
SC_MAXIMIZE: {isso daqui faz com que ao você maximizar a tela ele não maximize ela mas sim deixá-la como está tornando-a apenas visível}
begin
Self.Visible:= True;
end
else
Inherited
end;
end;

{Quando dar um duplo clique sobre o ícone da aplicação, destruímos este mesmo ícone e exibimos o formulário principal. Isto só funciona se implementarmos um manipulador para as Mensagens WMTrayIcon, que é o que faremos abaixo.

Lembra-se da constante declarada no ínicio de nossa Unit?
Pois bem, ela é passada como parâmetro para esta procedure.}
procedure TForm1.WMTrayIcon(var Msg: TMessage);
var
Pt: TPoint;
begin
if (Msg.LParam = WM_RBUTTONDOWN) then { faz com que ao você clicar com o botão direito do mouse no ícone do seu programa que está no Tray ele faça aparecer um PopupMenu, que nada mais é do que aqueles pequenos retângulos verticais que aparecem quando você clica com o botão direito, por exemplo, num espaço vazio da sua área de trabalho, onde aparecem várias opções. }
begin
GetCursorPos(Pt);
PopupMenu.Popup(Pt.X, Pt.Y);
PopupMenu.AutoPopup:= False;
end
else
if (Msg.LParam = WM_LBUTTONDBLCLK) then {isso daqui deixa seu formulário invisível e envia seu programa para o Tray ao clicar com o botão esquerdo do mouse duas vezes sobre o ícone do seu programa que está no Tray. Para que, em vez de ter que clicar duas vezes, clicar apenas uma vez (isso eu também não encontrei na Internet) você deverá mudar onde está excrito WM_LBUTTONDBLCLK para WM_LBUTTONDOWN.}
begin
Self.Visible:= True;
DestroyIcone;
end;
end;

OBS: Quando for necessário criar ou destruir nosso ícone que fica no Tray, chamaremos as procedures CriaIcone e DestroyIcone respectivamente. A API Shel_NotifyIcon requer um ponteiro para uma variável do tipo TNotifyIconData, declarada na Unit ShellApi.

5º passo: Adicione um componente TPopupMenu e altere seu nome para PopupMenu

Obs: Nesse componente(PopupMenu) você vai adicionar as opções que devem aparecer quando o usuario clicar com o botão direito do mouse sobre o icone da sua aplicação que esta ao lado do relógio.
Exemplo: Sair, Configurações, Opções, Maximixar e etc...

Obs2: Caso você não coloque o componente PopupMenu no seu formulario, isso irá gerar um erro de acesso a memória quando você clicar com o botão direito do mouse sobre o icone da sua aplicação que ficará do lado do relógio do computador.
Sendo assim, não se esqueça de colocar esse componente(PopupMenu).

------------------------------------//--------//--------------------------------------------------


Pronto, acabou. UFA!!! Cansei...

Espero que isso ajude a muitas pessoas e qualquer dúvida ou erro que eu cometi ou segustão ou
erro que deu ao rodar o programa ou outra coisa qualquer é só deixar nos comentários ou me enviar um e-mail: imdm94@hotmail.com

Mais dicas sobre "O seu programa no Tray" nos posts posteriores.

Abraços,

Imdm

6 comentários:

Anônimo disse...

Excelente dica meu amigo. Estava justamente procurando por isso.
Muito obrigado.

Anônimo disse...

VLW PELO POST MANO... EXCELENTE AJUDA....

Anônimo disse...

Ajudou bastante. Parabéns. Mas não estou conseguindo fazer ele minimizar através de um botão no evento OnKeyDown, por exemplo. Se dou um Application.Minimize ele minimiza normalmente, sem mandar para o systray. Alguem já fez isso.

Anônimo disse...

Excelente post amigo....me ajudou bastante..parabens..

Julio disse...

Kra...me ajudou muito...obrigado e parabéns!

Anônimo disse...

Parabéns pela dica. Para quem utiliza o delphi xe a diante, na linha:
SizeOf(TNotifyIconData);
mude para
System.SizeOf(TNotifyIconData);

Postar um comentário