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 ExitString
Przy 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: DWORD
Po 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: DWORD
Gdy 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