![]() |
Wyjście Spis treści Poprzedni Następny
Autor:
©Iczelion |
©2008 mgr
Jerzy Wałaszek
|
Na tej lekcji poznamy sposoby umieszczania ikon w zasobniku systemowym (system tray) oraz jak tworzyć i korzystać z menu wyskakującego (popup).

Kod źródłowy możesz pobrać {z tego archiwum}.
Zasobnik systemowy jest prostokątnym obszarem na pasku zadań, gdzie przebywa kilka ikon. Zwykle powinieneś tam zobaczyć przynajmniej cyfrowy zegar.
![]()
Ty również możesz tam umieszczać swoje ikony. Poniżej przedstawiam krok po kroku jak tego dokonać:
NOTIFYICONDATA STRUCT
cbSize DWORD ?
hwnd DWORD ?
uID DWORD ?
uFlags DWORD ?
uCallbackMessage DWORD ?
hIcon DWORD ?
szTip BYTE 64 DUP (?)
NOTIFYICONDATA ENDS
Shell_NotifyIcon PROTO dwMessage:DWORD ,pnid:DWORD
Jeśli chcesz dodać ikonę do zasobnika, użyj wiadomości NIM_ADD, jeśli chcesz ikonę usunąć, użyj NIM_DELETE.
To wszystko. Lecz częściej nie interesuje cię jedynie umieszczenie tam ikony. Chcesz mieć możliwość odpowiadania na zdarzenia myszki ponad ikoną zasobnika. Możesz tego dokonać obsługując wiadomość, którą określiłeś w polu uCallbackMessage struktury NOTIFYICONDATA.
| Wiadomość uCallbackMessage | |
|---|---|
| wParam | Zawiera numer ID ikony. Jest to ta sama wartość, którą wstawiasz w pole uID struktury NOTIFYICONDATA. |
| lParam | Młodsze słowo zawiera wiadomość myszki. Na przykład, jeżeli użytkownik kliknął prawym przyciskiem na tę ikonę, lParam będzie zawierało WM_RBUTTONDOWN. |
Jednakże większość ikon zasobnika wyświetla rozwijane menu (kontekstowe), gdy użytkownik kliknie je prawym przyciskiem myszki. Możemy zaimplementować tę cechę tworząc rozwijane menu, a następnie wywołując TrackPopupMenu w celu wyświetlenia go. Oto niezbędne kroki:
Uwaga: Unikaj dwóch dokuczliwych zwyczajów menu wyskakującego stosowanego z ikoną zasobnika:
Plik TRAYICON.ASM
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
INCLUDE \masm32\include\windows.inc
INCLUDE \masm32\include\user32.inc
INCLUDE \masm32\include\kernel32.inc
INCLUDE \masm32\include\shell32.inc
INCLUDELIB \masm32\lib\user32.lib
INCLUDELIB \masm32\lib\kernel32.lib
INCLUDELIB \masm32\lib\shell32.lib
WinMain PROTO :DWORD, :DWORD, :DWORD, :DWORD
.CONST
WM_SHELLNOTIFY EQU WM_USER + 5
IDI_TRAY EQU 0
IDM_RESTORE EQU 1000
IDM_EXIT EQU 1010
.DATA
ClassName DB "TrayIconWinClass", 0
AppName DB "Ikona Zasobnika Systemowego", 0
RestoreString DB "&Przywróć", 0
ExitString DB "&Zakończ program", 0
.DATA?
hInstance D ?
note NOTIFYICONDATA <>
hPopupMenu DD ?
.CODE
start:
INVOKE GetModuleHandle, NULL
mov hInstance, eax
INVOKE WinMain, hInstance, NULL, NULL, SW_SHOWDEFAULT
INVOKE ExitProcess, eax
WinMain PROC hInst: HINSTANCE,\
hPrevInst: HINSTANCE,\
CmdLine: LPSTR,\
CmdShow: DWORD
LOCAL wc : WNDCLASSEX
LOCAL msg : MSG
LOCAL hwnd : HWND
mov wc.cbSize, SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW OR CS_VREDRAW OR CS_DBLCLKS
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground, COLOR_APPWORKSPACE
mov wc.lpszMenuName, NULL
mov wc.lpszClassName, OFFSET ClassName
INVOKE LoadIcon, NULL, IDI_APPLICATION
mov wc.hIcon, eax
mov wc.hIconSm, eax
INVOKE LoadCursor, NULL, IDC_ARROW
mov wc.hCursor, eax
INVOKE RegisterClassEx, ADDR wc
INVOKE CreateWindowEx, WS_EX_CLIENTEDGE,\
ADDR ClassName, ADDR AppName,\
WS_OVERLAPPED + WS_CAPTION + \
WS_SYSMENU + WS_MINIMIZEBOX + \
WS_MAXIMIZEBOX + WS_VISIBLE,\
CW_USEDEFAULT, CW_USEDEFAULT, 350, 200,\
NULL, NULL, hInst, NULL
mov hwnd, eax
.WHILE TRUE
INVOKE GetMessage, ADDR msg, NULL, 0, 0
.BREAK .IF (!eax)
INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg
.ENDW
mov eax, msg.wParam
ret
WinMain ENDP
WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL pt: POINT
LOCAL rect: RECT
.IF uMsg==WM_CREATE
INVOKE CreatePopupMenu
mov hPopupMenu, eax
INVOKE AppendMenu, hPopupMenu, MF_STRING, IDM_RESTORE, ADDR RestoreString
INVOKE AppendMenu, hPopupMenu, MF_STRING, IDM_EXIT, ADDR ExitString
.ELSEIF uMsg==WM_DESTROY
INVOKE DestroyMenu, hPopupMenu
INVOKE PostQuitMessage, NULL
.ELSEIF uMsg==WM_SIZE
.IF wParam==SIZE_MINIMIZED
mov note.cbSize, SIZEOF NOTIFYICONDATA
push hWnd
pop note.hwnd
mov note.uID, IDI_TRAY
mov note.uFlags, NIF_ICON + NIF_MESSAGE + NIF_TIP
mov note.uCallbackMessage, WM_SHELLNOTIFY
INVOKE LoadIcon, NULL, IDI_WINLOGO
mov note.hIcon, eax
INVOKE lstrcpy, ADDR note.szTip, ADDR AppName
INVOKE ShowWindow, hWnd, SW_HIDE
INVOKE Shell_NotifyIcon, NIM_ADD, ADDR note
.ENDIF
.ELSEIF uMsg==WM_COMMAND
.IF lParam==0
INVOKE Shell_NotifyIcon, NIM_DELETE, ADDR note
mov eax, wParam
.IF ax==IDM_RESTORE
INVOKE ShowWindow, hWnd, SW_RESTORE
.ELSE
INVOKE DestroyWindow, hWnd
.ENDIF
.ENDIF
.ELSEIF uMsg==WM_SHELLNOTIFY
.IF wParam==IDI_TRAY
.IF lParam==WM_RBUTTONDOWN
INVOKE GetCursorPos, ADDR pt
INVOKE SetForegroundWindow, hWnd
INVOKE TrackPopupMenu, hPopupMenu,\
TPM_RIGHTALIGN OR TPM_RIGHTBUTTON,\
pt.x, pt.y, NULL, hWnd, NULL
INVOKE PostMessage, hWnd, WM_NULL, 0, 0
.ELSEIF lParam==WM_LBUTTONDBLCLK
INVOKE SendMessage, hWnd, WM_COMMAND, IDM_RESTORE, 0
.ENDIF
.ENDIF
.ELSE
INVOKE DefWindowProc, hWnd, uMsg, wParam, lParam
ret
.ENDIF
xor eax, eax
ret
WndProc ENDP
END start
Program wyświetli proste okno. Gdy klikniesz przycisk minimalizacji, program schowa okno i umieści ikonę w zasobniku systemowym. Gdy podwójnie klikniesz myszką tę ikonę, program odtworzy okno i usunie ikonę z zasobnika systemowego. Gdy klikniesz ją prawym przyciskiem myszki, zostanie wyświetlone menu wyskakujące. Możesz z niego wybrać opcję odtworzenia programu lub zakończenia jego pracy.
.IF uMsg==WM_CREATE
INVOKE CreatePopupMenu
mov hPopupMenu, eax
INVOKE AppendMenu, hPopupMenu, MF_STRING, IDM_RESTORE, ADDR RestoreString
INVOKE AppendMenu, hPopupMenu, MF_STRING, IDM_EXIT, ADDR ExitStringPrzy tworzeniu okna powstaje wyskakujące menu i dołączane są do niego dwa elementy. Funkcja AppendMenu posiada następującą składnię:
AppendMenu PROTO hMenu: DWORD,\
uFlags: DWORD,\
uIDNewItem: DWORD,\
lpNewItem: DWORDPo utworzeniu wyskakującego menu główne okno czeka cierpliwie aż użytkownik kliknie przycisk minimalizacji.
Gdy okno jest minimalizowane, otrzymuje ono wiadomość WM_SIZE z wartością SIZE_MINIMIZED w wParam.
.ELSEIF uMsg==WM_SIZE
.IF wParam==SIZE_MINIMIZED
mov note.cbSize, SIZEOF NOTIFYICONDATA
push hWnd
pop note.hwnd
mov note.uID, IDI_TRAY
mov note.uFlags, NIF_ICON + NIF_MESSAGE + NIF_TIP
mov note.uCallbackMessage, WM_SHELLNOTIFY
INVOKE LoadIcon, NULL, IDI_WINLOGO
mov note.hIcon, eax
INVOKE lstrcpy, ADDR note.szTip, ADDR AppName
INVOKE ShowWindow, hWnd, SW_HIDE
INVOKE Shell_NotifyIcon, NIM_ADD, ADDR note
.ENDIF
Korzystamy z tej okazji do wypełnienia struktury NOTIFYICONDATA. Wartość IDI_TRAY jest po prostu stałą zdefiniowaną na samym początku tekstu źródłowego programu. Nie jest ona ważna, ponieważ posiadamy tylko jedną ikonę zasobnika. Lecz jeśli w zasobniku chcemy umieszczać kilka ikon, to dla każdej z nich będziemy potrzebowali dla każdej z nich osobnego numeru ID. W polu uFlags umieszczamy wszystkie znaczniki, ponieważ określamy ikonę (NIF_ICON), prywatną wiadomość (NIF_MESSAGE) oraz tekst podpowiedzi (NIF_TIP). Wartość WM_SHELLNOTIFY jest po prostu prywatną wiadomością zdefiniowaną jako WM_USER + 5. Wartość ta nie jest istotna o ile nie koliduje z innymi wiadomościami. Tutaj zastosowałem ikonę logo Windows, lecz może to być dowolna inna ikona. Po prostu załaduj ją z pliku zasobów przy pomocy funkcji LoadIcon i umieść zwrócony przez nią uchwyt w polu hIcon. Na koniec wypełniamy pole szTip tekstem, który ma być wyświetlany przez powłokę, gdy kursor myszki zatrzymuje się ponad ikoną zasobnika.
Ukrywamy główne okno, aby dać iluzję "minimalizacji do ikony zasobnika".
Następnie wywołujemy Shell_NotifyIcon z wiadomością NIM_ADD, aby dodać tę ikonę do zasobnika systemowego.
Teraz nasze okno główne zostało ukryte a ikona umieszczona w zasobniku systemowym. Gdy umieścisz kursor myszki na tej ikonie, pojawi się tekst podpowiedzi wyświetlający nazwę naszej aplikacji, którą umieściliśmy w polu szTi. Następnie jeśli klikniesz podwójnie na tej ikonie, pojawi się główne okno a zniknie ikona zasobnika.
.ELSEIF uMsg==WM_SHELLNOTIFY
.IF wParam==IDI_TRAY
.IF lParam==WM_RBUTTONDOWN
INVOKE GetCursorPos, ADDR pt
INVOKE SetForegroundWindow, hWnd
INVOKE TrackPopupMenu, hPopupMenu,\
TPM_RIGHTALIGN OR TPM_RIGHTBUTTON,\
pt.x, pt.y, NULL, hWnd, NULL
INVOKE PostMessage, hWnd, WM_NULL, 0, 0
.ELSEIF lParam==WM_LBUTTONDBLCLK
INVOKE SetForegroundWindow, hWnd
INVOKE SendMessage, hWnd, WM_COMMAND, IDM_RESTORE, 0
.ENDIF
.ENDIF
Gdy powstanie jakieś zdarzenie myszki ponad ikoną zasobnika, twoje okno otrzyma wiadomość WM_SHELLNOTIFY, która jest prywatną wiadomością określoną w polu uCallbackMessage. Przypomnij sobie, iż przy otrzymywaniu tej wiadomości parametr wParam zawiera numer ID ikony zasobnika, a lParam zawiera właściwą wiadomość myszki. W kodzie powyżej sprawdzamy najpierw, czy wiadomość ta pochodzi od interesującej nas ikony zasobnika. Jeśli tak, to sprawdzamy właściwą wiadomość myszki. Ponieważ interesuje nas jedynie kliknięcie ikony prawym przyciskiem myszki lub podwójne kliknięcie lewym przyciskiem, obsługujemy tylko wiadomości WM_RBUTTONDOWN oraz WM_LBUTTONDBLCLK.
Jeśli wiadomością myszki jest WM_RBUTTONDOWN, wywołujemy funkcję GetCursorPos, aby otrzymać bieżącą pozycję ekranową kursora myszki. Gdy funkcja powraca, struktura POINT jest wypełniona współrzędnymi kursora myszki na ekranie. Przez współrzędne ekranowe rozumiem współrzędne całego ekranu bez oglądania się na jakieś granice okien. Przykładowo, jeśli rozdzielczość ekranu wynosi 1024x768, to dolny prawy narożnik ekranu będzie miał współrzędne x=1023 i y=767. Jeśli chcesz zamienić współrzędne ekranowe na współrzędne w obszarze okna, użyj funkcji ScreenToClient.
Jednakże naszym celem jest wyświetlenie menu wyskakującego na bieżącej pozycji kursora myszki przy pomocy wywołania funkcji TrackPopupMenu call, a ona wymaga współrzędnych ekranowych, zatem możemy bezpośrednio wykorzystać współrzędne zwrócone przez GetCursorPos.
Funkcja TrackPopupMenu ma następującą składnię:
TrackPopupMenu PROTO hMenu: DWORD,\
uFlags: DWORD,\
x: DWORD,\
y: DWORD,\
nReserved: DWORD,\
hWnd: DWORD,\
prcRect: DWORDGdy użytkownik kliknie podwójnie na ikonie zasobnika, wysyłamy wiadomość WM_COMMAND do naszego własnego okna określając IDM_RESTORE w celu symulacji wyboru przez użytkownika elementu menu Przywróć w wyskakującym menu, co spowoduje odtworzenie okna oraz usunięcie ikony z zasobnika systemowego. Aby otrzymywać wiadomości o podwójnym kliknięciu myszką, okno główne musi posiadać styl CS_DBLCLKS. Przed wysłaniem tej wiadomości konieczne jest wywołanie funkcji SetForegroundWindow, która ustawi nasze okno na pierwszym planie. W przeciwnym wypadku okno po odtworzeniu mogłoby być zakryte, a kliknięcie w przycisk programu na pasku zadań odsyłało by je z powrotem do zasobnika systemowego.
INVOKE Shell_NotifyIcon, NIM_DELETE, ADDR note
mov eax, wParam
.IF ax==IDM_RESTORE
INVOKE ShowWindow, hWnd, SW_RESTORE
.ELSE
INVOKE DestroyWindow, hWnd
.ENDIF
Gdy użytkownik wybierze element menu Przywróć, usuwamy ikonę zasobnika wywołując ponownie funkcję Shell_NotifyIcon, tym razem określamy jako wiadomość NIM_DELETE. Następnie odtwarzamy główne okno do stanu pierwotnego. Jeśli użytkownik wybierze element menu Zakończ program, również usuwamy ikonę z zasobnika i usuwamy okno główne wywołując DestroyWindow.
Ta sama aplikacja w Pascalu:
{********************************
** I Liceum Ogólnokształcące **
** w Tarnowie **
** mgr Jerzy Wałaszek **
********************************}
program TrayIcon;
uses Windows;
const
WM_SHELLNOTIFY = WM_USER + 5;
NIF_MESSAGE = 1;
NIF_ICON = 2;
NIF_TIP = 4;
NIM_ADD = 0;
NIM_DELETE = 2;
IDI_TRAY = 0;
IDM_RESTORE = 1000;
IDM_EXIT = 1010;
ClassName = 'TrayIconWinClass';
AppName = 'Ikona Zasobnika Systemowego';
RestoreString = '&Przywróć';
ExitString = '&Zakończ program';
var
hInstance : HINST;
note : NOTIFYICONDATA;
hPopupMenu : longword;
function WndProc(hWnd:HWND;uMsg:UINT;wParam:WPARAM;lParam:LPARAM) : longint;
var
pt : POINT;
rect: RECT;
begin
Result := 0;
case uMsg of
WM_CREATE:
begin
hPopupMenu := CreatePopupMenu;
AppendMenu(hPopupMenu,MF_STRING,IDM_RESTORE,RestoreString);
AppendMenu(hPopupMenu,MF_STRING,IDM_EXIT,ExitString);
end;
WM_DESTROY:
begin
DestroyMenu(hPopupMenu);
PostQuitMessage(0);
end;
WM_SIZE:
if wParam = SIZE_MINIMIZED then
begin
note.cbSize := sizeof(NOTIFYICONDATA);
note.wnd := hWnd;
note.uID := IDI_TRAY;
note.uFlags := NIF_ICON + NIF_MESSAGE + NIF_TIP;
note.uCallbackMessage := WM_SHELLNOTIFY;
note.hIcon := LoadIcon(0,IDI_WINLOGO);
note.szTip := AppName;
ShowWindow(hWnd,SW_HIDE);
Shell_NotifyIcon(NIM_ADD,@note);
end;
WM_COMMAND:
if lParam = 0 then
begin
Shell_NotifyIcon(NIM_DELETE,@note);
if (wParam and $ffff) = IDM_RESTORE then
ShowWindow(hWnd,SW_RESTORE)
else
DestroyWindow(hWnd);
end;
WM_SHELLNOTIFY:
if wParam = IDI_TRAY then
case lParam of
WM_RBUTTONDOWN:
begin
GetCursorPos(pt);
SetForegroundWindow(hWnd);
TrackPopupMenu(hPopupMenu,TPM_RIGHTALIGN or TPM_RIGHTBUTTON,pt.x,pt.y,0,hWnd,rect);
PostMessage(hWnd,WM_NULL,0,0);
end;
WM_LBUTTONDBLCLK:
SendMessage(hWnd,WM_COMMAND,IDM_RESTORE,0);
end;
else Result := DefWindowProc(hWnd,uMsg,wParam,lParam);
end;
end;
function WinMain(hInst,hPrevInst:HINST;CmdLine:LPSTR;CmdShow:DWORD) : longint;
var
wc : WNDCLASSEX;
msg : MSG;
hwnd: HWND;
begin
with wc do
begin
cbSize := sizeof(WNDCLASSEX);
style := CS_HREDRAW or CS_VREDRAW or CS_DBLCLKS;
lpfnWndProc := @WndProc;
cbClsExtra := 0;
cbWndExtra := 0;
hInstance := hInst;
hbrBackground := COLOR_APPWORKSPACE;
lpszMenuName := 0;
lpszClassName := ClassName;
hIcon := LoadIcon(0,IDI_APPLICATION);
hIconSm := hIcon;
hCursor := LoadCursor(0,IDC_ARROW);
end;
RegisterClassEx(wc);
hwnd := CreateWindowEx(WS_EX_CLIENTEDGE,ClassName,AppName,
WS_OVERLAPPED + WS_CAPTION + WS_SYSMENU + WS_MINIMIZEBOX +
WS_MAXIMIZEBOX + WS_VISIBLE,CW_USEDEFAULT,CW_USEDEFAULT,
350,200,0,0,hInst,0);
while GetMessage(msg,0,0,0) do
begin
TranslateMessage(msg);
DispatchMessage(msg);
end;
Result := msg.wParam;
end;
begin
hInstance := GetModuleHandle(0);
ExitProcess(WinMain(hInstance,0,0,SW_SHOWDEFAULT));
end.
|
Autorem
kursu jest
Iczelion. Kurs
programowania Windows znalazł się na serwerze I LO w Tarnowie za pisemną
zgodą autora. |
![]() | I Liceum Ogólnokształcące |
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe