Jak dodać ikonę do traya

HIHER

Są dwie rzeczy, które trzeba wziąć pod uwagę tworząc aplikację do tray'a. Pierwsza to ukrycie aplikacji przed Windows. Mimo, że aplikacje takie wyglądają i zachowują się jak zwykłe aplikacje Windows, nie można się na nie przełączyć przy użyciu Alt-Tab ani nie mają swojego przycisku na pasku zadań. Tym zajmiemy się najpierw.
Każde okno posiadające styl WS_EX_TOOLWINDOW ani nie ma przycisku na pasku zadań ani nie można się na nie przełączyć. Z początku może wydawać się właściwym ustawienie tego stylu przy użyciu CreateParams. Niestety nie zadziała to dla formy. Tu mała dygresja. Główna forma aplikacji nie jest oknem (w terminologii Windows) aplikacji. Obiekt aplikacji ma swoje własne okno - nie można go zobaczyć
ale ono tam jest. To jest właśnie to okno, do którego należy przypisać styl WS_EX_TOOLWINDOW. Gdzie więc należy wstawić kod? Oczywiście w źródle projektu. Po wybraniu View|Project Source należy skopiować poniższy kod:

program Project1;  
 uses 
Forms, Unit1 in 'Unit1.pas' {Form1}, 
Windows;//To jest wymagane aby znana była stała WS_EX_TOOLWINDOW i pozostałe         
 
{$R *.RES}
 
 var
 ExtendedStyle : Integer;  //Deklaracja zmiennej do przyjęcia informacji o stylu okna
 
 begin
Application.Initialize;
 //Pobranie informacji o oknie aplikacji przy użyciu GetWindowLong
 ExtendedStyle:=GetWindowLong(Application.Handle, GWL_EXSTYLE);
 
//Teraz ustawiamy styl rozszerzony przy użyciu operacji na bitach
//Przekształca to okno z okna-aplikacji do okna-narzędzia
SetWindowLong(Application.Handle,GWL_EXSTYLE,ExtendedStyle or WS_EX_TOOLWINDOW and 
not WS_EX_APPWINDOW);
            Application.CreateForm(TForm1, Form1); 
            Application.Run;
              end.

A teraz aby utworzyć właściwy efekt aplikacji w trayu będziemy potrzebowali przede wszystkim głównej formy aplikacji. Połóż na formie komponent TPopupMenu. Będzie to główny interfejs do naszej aplikacji. Popatrz na poniższy kod:

{ Poniższe umieszcza aplikację w trayu. Jest to główna forma aplikacji. Posiada ona menu popup używane do wyświetlenia formy i zamknięcia aplikacji. Używając modułu ShellApi w prosty sposób pokażemy ikonę aplikacji w trayu i spowodujemy aby reagowała na kliknięcia myszą } 
 
              unit Unit1;
             interface
 
             uses
               Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
               ShellAPI, ExtCtrls, Menus;
 
              type
               TForm1 = class(TForm)
               PopupMenu1: TPopupMenu;
               ShowMainForm1: TMenuItem;
               N1: TMenuItem;
               ExitApplication1: TMenuItem;
              procedure FormCreate(Sender: TObject);
             procedure ShowMainForm1Click(Sender: TObject);
             procedure FormClose(Sender: TObject; var Action: TCloseAction);
              procedure ExitApplication1Click(Sender: TObject);
              private
              procedure WndProc(var Msg : TMessage); override;
              public
              IconNotifyData : TNotifyIconData;
              end;
 
            var
              Form1: TForm1;
 
              implementation
 
              {$R *.DFM}
 
              procedure TForm1.FormCreate(Sender: TObject);
              begin
               // Zostawiamy tylko przycisk zamykający okno
               BorderIcons := [biSystemMenu];
 
              // Teraz wypełniamy rekord IconNotifyData tak aby przyjmował
              // komunikaty wysyłane do aplikacji i pokazywał dymki podpowiedzi.
              with IconNotifyData do begin
              hIcon:=Application.Icon.Handle;
              uCallbackMessage:=WM_USER+1;
              cbSize:=SizeOf(IconNotifyData);
             Wnd:=Handle;
             uID:=100;
             uFlags:=NIF_MESSAGE+NIF_ICON+NIF_TIP;
             end;
              // Kopiujemy tytuł aplikacji jako ;dymek;
               StrPCopy(IconNotifyData.szTip, Application.Title);
 
              // Dodajemy ikonę do traya
               Shell_NotifyIcon(NIM_ADD,@IconNotifyData);
              end;
 
              procedure TForm1.WndProc(var Msg : TMessage);
              var
             p : TPoint;
              begin
              if (Msg.Msg=WM_USER+1) and (Msg.lParam=WM_RBUTTONDOWN) then
               begin
               GetCursorPos(p);
              PopupMenu1.Popup(p.x, p.y);
              end; inherited;
             end;
 
              // To jedna z procedur obsługi elementów menu
              procedure TForm1.ShowMainForm1Click(Sender: TObject);
              begin
               Form1.Show;
              end;
 
              procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
              begn
               Action := caNone;
               Form1.Hide;
              end;
 
              procedure TForm1.ExitApplication1Click(Sender: TObject);
              begin
               Shell_NotifyIcon(NIM_DELETE, @IconNotifyData);
               Application.ProcessMessages;
               Application.Terminate;
              end;
              end.

Jak widać nie ma wiele do zrobienia. Ale ważne jest aby rozumieć co zrobiliśmy w metodzie Create i jakie znaczenie ma rekord IconNotifyData. Jest to rekord zdefiniowany w module ShellAPI, który przechowuje informację o ikonie w trayu. Zauważ flagi, których użyliśmy: NIF_MESSAGE + NIF_ICON + NIF_TIP. Oznaczają one kolejno: obsługę komunikatów dla aplikacji, pokazywanie ikony aplikacji i pokazywanie dymku z podpowiedzią.
Następna sprawa to nadpisanie procedury WndProc (skrót od WindowProcedure). Dostaje ona wszystkie komunikaty przesyłane do okna i zachowuje się jak centralna rozdzielnia komunikatów. Można przejąć obsługę komunikatu pisząc własną jego obsługę i wywołując odziedziczoną procedurę. Przy obsłudze komunikatu sprawdzamy czy jest to nasz własny (wm_User+1) zdefiniowany w zmiennej IconNotifyData oraz czy nastąpiło
kliknięcie prawym przyciskiem myszy. Pozostałe komunikaty przesyłamy bez zmian.[...]

17 komentarzy

czesc jest taki kod
procedure TForm1.WndProc(var Msg : TMessage);

          var

            p : TPoint;

          begin

            if (Msg.Msg=WM_USER+1)and(Msg.lParam=WM_RBUTTONDOWN) then

            begin

             GetCursorPos(p);

             PopupMenu1.Popup(p.x, p.y);

            end; inherited;

          end;

          // To jedna z procedur obsługi elementów menu

          procedure TForm1.ShowMainForm1Click(Sender: TObject);

          begin

            Form1.Show;

          end;

i mam pytanie gdzie go doda??

Mi wyskakuje seria błędów! Połowę kodu zaznacza na czerwono!

nie wiem co się dzieje ale nie wyświetla mi popupmenu, reszta śmiga dobrze.

Delphi 2006 ma wbudowany komponent do tego (coś jak w Builderze), jak macie możliwość żeby go użyć to polecam, jest dużo wygodniejszy :)

Wszystko fajnie, tylko nie usuwa aplikacji z ALT+TAB, jak zrobic zeby usuwalo??

Shell_NotifyIcon(NIM_DELETE,@icon);

Witam wszystkich.
Powiedzcie mi jak mogę usunąć ikonkę z tray'a.
Dzięki..

Nie chce pisać na temat tego ArtuMam zasadnicze pytanie jak dodać pogram do treja który nie zawiera Formy bo jak wiadomo program skompilowany bez bibliotek alboz samym WINDOWS zajmuje jakieś 16 Kb w Delphi 7

Żeby menu znikało po kliknięciu np. na pulpicie trzeba przed pokazaniem menu (w funkcji WndProc) wywołać funkcję SetForegroundWindow(Handle):
if (Msg.Msg=WM_USER+1)and(Msg.lParam=WM_RBUTTONDOWN) then
begin
SetForegroundWindow(Handle)
GetCursorPos(p);
......

Ten tekst widziałem już w wielu faqach (identyczny), ale niestety to rozwiązanie jest złe!
Popup nie znika jesli klikniemy na pulpit, a powinien.

no dobra, niby dziala ale teraz pisze ze file not found *.dcu .........

gdzie ja mam wstawci pierwsza czesc kodu??>
nie mam czegos takiego jak view|source code

mam wstawic do Unit1.pas??

wstawilem tylko 2 czesc, dziala ale nie wyswietla mojego popupmenu, jak zrobic zeby wyswietlało?

gdzie ja mam wstawci pierwsza czesc kodu??>
nie mam czegos takiego jak view|source code

mam wstawic do Unit1.pas??

wstawilem tylko 2 czesc, dziala ale nie wyswietla mojego popupmenu, jak zrobic zeby wyswietlało?

Ah tu był mój komentarz ale już go niema bo źle zrozumiałem intecje pop. autrów komentarzy :) czyli ten art był przeniesiony?

nie, to się raczej nadaje do FAQ :) A chyba nawet tam jest coś podobnego...

Ludzie, to sie nadaje do dzialu Gotowce, a nie tutaj!!!