Ikona na tacy systemowej w Delphi

Uwaga jeśli w tekscie wystąpi np.

Jakiś tekst (->)
(->) inny tekst

oznacza to, że te linie znajdują się w jednym we4rsie, tylko ze względy na szerokość magazynu musiały zostać podzielone...

Teoria

Taca systemowa (inaczej Windows Tray) to niewielki prostokątny obszar w prawym dolnym rogu ekranu (znajduje się tam zegar systemowy i kilka ikonek - głośniczek i coś jeszcze). W tym artykule opiszę jak umieścić tam ikonę własnego programu, jak sprawić aby program nie miał szufladki na pasku zadań i jak obsługiwać komunikaty od ikonki. Wszystko będę popierał kodem w Delphi 5.0, ale będzie chodziło też na wcześniejszych wersjach i po pewnych poprawkach w C++ Builderze.

Program (czyt. jego szkielet), który przy okazji powstanie to Podręcznik programisty, czyli zestaw okien (mojego autorstwa) pomagający w tworzeniu programów. 

Czarna robota

A więc tworzymy nowy projekt aplikacji i zapisujemy go jako pp.dpr (najlepiej w specjalnie do tego utworzonym katalogu pp). Zapisujemy także unit1.pas . 

Najpierw należy sprawić, aby w czasie uruchamiania aplikacji nie pojawiało się jej główne okno i żeby nie pojawiała się szufladka na pasku zadań. W tym miejscu namawiam do nietestowania naszej aplikacji, zanim ją dokończymi, gdyż mniej doświadczeni będą mieli problemy z zamknięciem niewidocznej aplikacji. 

Aby okno się nie pojawiło należy umieścić następującą linię w kodzie pliku pp.dpr (między wywołaniami funkcji Initialize i CreateForm):

Application.ShowMainForm:=false;

To powinno załatwić sprawę. Jednak we wczesniejszych wersjach należy umieścić zamiast jednej linii cały kod:

w sekcji var:
StylOkna : Integer;
między Initialize i CreateForm:
StylOkna:=GetWindowLong(Application.Handle,GWL_EXSTYLE);
SetWindowLong(Application.Handle,GWL_EXSTYLE, (->)
(->)StylOkna or WS_EX_TOOLWINDOW and not WS_EXE_APPWINDOW);

Musimy wywołać te funkcje ponieważ w Delphi główna forma aplikacji nie jest właściwym oknem aplikacji. To okno jest wykorzystywane przez obiekt Application i my nie mamy do niego dostępu. Nie widzimy go również, gdyż ma szerokość i wysokość równą 0.

Gdy pojawianie okna mamy już z głowy przystępujemy do umieszczenia ikonki w Tray'u. Zrobimy to oczywiście w konstruktorze formy. Przedtem jednak zmieniamy nazwę Form1 na MainForm (tak dla jaj). Klikamy dwukrotnie na formie i jesteśmy w środku zdarzenia FormCreate.
Do umieszczenia ikonki będzie nam potrzebna funkcja API o nazwie Shell_NotifyIcon z modułu ShellApi (należy go dodać w sekcji uses). Ikona jaka umiescimy na tacy będzie zarazrem ikona aplikacji (Możesz ją w tym momencie zmienić na dowolną).
Na potrzeby tej funkcji deklarujemy sobie też zmienna globalną typu TNotifyIconData:

IkonaNaTacy : TNotifyIconData;

Ma ona następującą strukturę:

TNotifyIconData = record
   cbSize : DWORD;                        - to rozmiar tego rekordu = sizeof(TNotifyIconData)
   Wnd : HWND;                             - to uchwyt okna, do którego będzie kierowany komunikat ikony   
   uID : UINT;                                  - to identyfikator ikony w przypadku, gdy aplikacji ma wiecej ikon na tacy
   uFlags : UINT;                              - flagi określające, które z nastepnych pól będą wypełnione, może być kombinacją          flag NIF_ADD, NIF_MESSAGE, NIF_TIP   
   uCallbackMessage : UINT;            - identyfikator komunikatu ikony
   hIcon : HICON;                            - uchwyt do obrazka ikony
   szTip : array[0..63] of AnsiChar;    - podpowiedź wysuwająca sie gdy myszka wejdzie w obszar ikony
end;

Musimy również zadeklarować stałą globalną, która będzie identyfikatorem komunikatu wysyłanego przez naszą ikonę (gdy użytkownik na nią kliknie).

const WM_IKONANATACY = WM_USER + 1;

Teraz możemy przystąpić do oprogramowania zdarzenia FormCreate. Umieszczmy tam następujący kod:

with IkonaNaTacy do
 begin
 cbSize:=sizeof(TNotifyIconData);
 Wnd:=Handle;
 uId:=0;
 uFlags:=NIF_ICON or NIF_MESSAGE or NIF_TIP;
 uCallBackMessage:=WM_IKONANATACY;
 szTip:='Podręcznik programisty';
 hIcon:=Application.Icon.Handle;
end;
Shell_NotifyIcon(NIM_ADD,@IkonaNaTacy);

Wyjaśnienia wymaga jeszcze funkcja Shell_NotifyIconData. Jako pierwszy parametr przyjmuje ona stałą, która mówi co chcemy zrobić. Jesli jest to NIM_ADD to chcemy wstawić ikonę, której dane wskazuje drugi parametr. Jeśli jest to NIM_DELETE to usuwamy ikonkę (podając jako drugi parametr wskaźnik na jakiś obiekt TNotifyIconData). Możemy też użyć flagi NIM_MODIFY aby zmienic jakąś cechę już umieszczonej ikony.

Mamy więc umieszczoną ikonę na tacy. Teraz należy zadbać, aby była usunięta, gdy aplikacja się zakończy. Robimy to w destruktorze formy FormDestroy:

Shell_NotifyIcon(NIM_DELETE,@IkonaNaTacy);

Wszystko jest cacy! Ale chwileczkę - co nam da ikona na tacy, gdy nie mamy z nią żadnego kontaktu. Oczywiście kontakt taki musimy utowrzyć. Załóżmy, ze chcemy, aby gdy użytkownik podwójnie kliknie lewym przyciskiem myszy pojawiała się MainForm, a gdy naciśnie prawy przycisk myszy aby wyskakiwało menu kontekstowe. Do tego celu posłuży nam identyfikator komunikatu WM_IKONANATACY. Tworzymy nową metodę klasy MainForm o prototypie:

procedure KOMUNIKAT_IKONANATACY(var Message : TMessage); (->)
(->)message WM_IKONANATACY;

i definicji:

procedure TMainForm.KOMUNIKAT_IKONANATACY (->)
(->)(var Message : TMessage);
var
 Punkt : TPoint;
begin
 case Message.LParam of
  WM_LBUTTONDBLCLK:
   MainForm.Show;
  WM_RBUTTONDOWN:
   begin
   GetCursorPos(Punkt);
   //pobiera współrzędne kursora myszy 
   MenuPodreczne.Popup(Punkt.x,Punkt.y);
   //powoduje wyskoczenie menu
   end;
 end;
end;

Aby wszystko działało należy jeszcze położyć na formie komponent TPopupMenu i nadac mu nazwę MenuPodreczne i dodac do niego własne pozycje.

Post Scriptum

Programy umieszczające się na tacy mogą być bardzo przydatne. Ja wykorzystuję właściwie tylko dwa programy mające na tacy swoje ikonki - jednym z nich jest skaner antywirusowy, a drugim mój własny - Podręcznik programisty.

Mr Bin
delfisajt@poczta.onet.pl
www.polbox.com/t/tplsoft

 

 Copyright © 2000 PTiK. Wszystkie prawa zastrzeżone.
 Kopiowanie tekstów w całości lub we fragmentach bez zgody redakcji i autorów zabronione.