Wyjście Spis treści Poprzedni Następny
Autor:
©Iczelion |
©2008 mgr
Jerzy Wałaszek
|
|
W tej lekcji nauczymy się odbierać i odpowiadać w naszej procedurze okna na zdarzenia związane z myszką. Przykładowy program będzie oczekiwał na kliknięcia lewym przyciskiem myszki i wyświetlał łańcuch tekstu dokładnie w miejscu kliknięcia na obszarze roboczym.
Pobierz plik z przykładem {z tego archiwum}.
Podobnie jak w przypadku danych z klawiatury system Windows wykrywa i wysyła powiadomienia o działaniach myszką, które są istotne dla każdego okna. Działania te obejmują kliknięcia lewym i prawym przyciskiem, ruch kursora ponad powierzchnią okna, podwójne kliknięcia. W przeciwieństwie do klawiatury, z której dane są kierowane do aktywnego w danej chwili okna, wiadomości myszki są przesyłane do dowolnego okna, nad którym w danej chwili znajduje się kursor myszki, bez względu na to, czy jest ono aktywne, czy nie. Dodatkowo są również wiadomości myszki dotyczące obszarów poza obszarem roboczym. Na szczęście zwykle możemy je spokojnie zignorować. Skupimy się tylko na wiadomościach dotyczących naszego obszaru roboczego.
Są dwie wiadomości dla każdego z przycisków myszki: WM_LBUTTONDOWN, WM_RBUTTONDOWN oraz WM_LBUTTONUP, WM_RBUTTONUP. Dla myszki z trzema klawiszami mamy również wiadomości WM_MBUTTONDOWN i WM_MBUTTONUP. Gdy kursor myszki przesuwa się ponad obszarem roboczym okna, system Windows wysyła wiadomości WM_MOUSEMOVE do okna pod kursorem.
Okno może otrzymywać wiadomości WM_LBUTTONDBCLK lub WM_RBUTTONDBCLK tylko wtedy, gdy jego klasa zawiera znacznik stylu CS_DBLCLKS, w przeciwnym razie okno to będzie jedynie otrzymywać ciąg wiadomości o wciśnięciu i zwolnieniu przycisków myszki.
We wszystkich wiadomościach myszki wartość IParam zawiera pozycję myszki. Młodsze słowo jest wartością współrzędnej x, a starsze słowo określa współrzędną y określone względem lewego górnego rogu obszaru roboczego okna. wParam określa stan przycisków myszki oraz klawiszy Shift i Ctrl.
.386 .MODEL FLAT, STDCALL OPTION CASEMAP:NONE WinMain PROTO :DWORD, :DWORD, :DWORD, :DWORD INCLUDE \masm32\include\windows.inc INCLUDE \masm32\include\user32.inc INCLUDE \masm32\include\kernel32.inc INCLUDE \masm32\include\gdi32.inc INCLUDELIB \masm32\lib\user32.lib INCLUDELIB \masm32\lib\kernel32.lib INCLUDELIB \masm32\lib\gdi32.lib .DATA ClassName DB "SimpleWinClass",0 AppName DB "Nasze pierwsze okno",0 MouseClick DB 0 ; 0=jeszcze nie było kliknięcia myszką .DATA? hInstance HINSTANCE ? CommandLine LPSTR ? hitpoint POINT <> .CODE start: INVOKE GetModuleHandle, NULL mov hInstance, eax INVOKE GetCommandLine mov CommandLine, eax INVOKE WinMain, hInstance, NULL, CommandLine, 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 mov wc.lpfnWndProc, OFFSET WndProc mov wc.cbClsExtra, NULL mov wc.cbWndExtra, NULL push hInst pop wc.hInstance mov wc.hbrBackground, COLOR_WINDOW+1 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, NULL, ADDR ClassName, ADDR AppName,\ WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,\ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,\ NULL, NULL, hInst, NULL mov hwnd, eax INVOKE ShowWindow, hwnd, SW_SHOWNORMAL INVOKE UpdateWindow, hwnd .WHILE TRUE INVOKE GetMessage, ADDR msg, NULL, 0, 0 .BREAK .IF (!eax) INVOKE DispatchMessage, ADDR msg .ENDW mov eax, msg.wParam ret WinMain ENDP WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM LOCAL hdc: HDC LOCAL ps: PAINTSTRUCT .IF uMsg==WM_DESTROY INVOKE PostQuitMessage, NULL .ELSEIF uMsg==WM_LBUTTONDOWN mov eax, lParam and eax, 0ffffh mov hitpoint.x, eax mov eax, lParam shr eax, 16 mov hitpoint.y, eax mov MouseClick, TRUE INVOKE InvalidateRect, hWnd, NULL, TRUE .ELSEIF uMsg==WM_PAINT INVOKE BeginPaint, hWnd, ADDR ps mov hdc, eax .IF MouseClick INVOKE lstrlen, ADDR AppName INVOKE TextOut, hdc, hitpoint.x, hitpoint.y,\ ADDR AppName, eax .ENDIF INVOKE EndPaint, hWnd, ADDR ps .ELSE INVOKE DefWindowProc, hWnd, uMsg, wParam, lParam ret .ENDIF xor eax, eax ret WndProc ENDP END start
.ELSEIF uMsg==WM_LBUTTONDOWN mov eax, lParam and eax, 0ffffh mov hitpoint.x, eax mov eax, lParam shr eax, 16 mov hitpoint.y, eax mov MouseClick, TRUE INVOKE InvalidateRect, hWnd, NULL, TRUE .ELSEIF uMsg==WM_PAINT
Procedura okna czeka na kliknięcie lewego przycisku myszki. Gdy otrzyma
wiadomość WM_LBUTTONDOWN,
lParam zawiera współrzędne kursora myszki w
obszarze roboczym okna. Procedura zachowuje te współrzędne w zmiennej typu
POINT, który jest zdefiniowany jako:
POINT STRUCT x DD ? y DD ? POINT ENDS
i ustawia znacznik MouseClick na
TRUE, co oznacza, iż było kliknięcie lewego
przycisku myszki nad obszarem roboczym okna.
mov eax, lParam and eax, 0ffffh mov hitpoint.x, eax
Ponieważ współrzędna x znajduje się w młodszym słowie
lParam, a pola struktury POINT
mają rozmiar 32 bitów, musimy wyzerować starsze słowo rejestru
eax przed umieszczeniem jego zawartości w
hitpoint.x.
mov eax, lParam shr eax, 16 mov hitpoint.y, eax
Ponieważ współrzędna y znajduje się w starszym słowie
lParam, musimy przemieścić ją do młodszego słowa
rejestru
eax przed umieszczeniem w
hitpoint.y. Wykonujemy to przesuwając zawartość
eax o 16 bitów w prawo.
Uwaga od tłumacza.
Opisane operacje można również przeprowadzić dużo prościej po prostu
zerując rejestr eax, a następnie pobierając do
jego części 16 bitowej słowo spod adresu lParam i
słowo spod adresu lParam+2, przesyłając zawartość
eax kolejno do pola x i y
struktury hitpoint. Odpowiedni fragment kodu jest
następujący:
xor eax, eax ;zerujemy rejestr 32 bitowy eax mov ax, WORD PTR lParam ;pobieramy współrzędną x kursora myszki mov hitpoint.x, eax ;przesyłamy wynik do struktury mov ax, WORD PTR lParam + 2 ;pobieramy współrzędną y mov hitpoint.y, eax ;przesyłamy do struktury y
Po zapamiętaniu pozycji myszki ustawiamy znacznik
MouseClick na TRUE, aby kod malujący w
sekcji WM_PAINT wiedział, iż wystąpiło kliknięcie
lewego klawisza myszki w obszarze roboczym okna i aby mógł wyrysować
łańcuch znaków na pozycji myszki. Następnie wywołujemy funkcję
InvalidateRect wymuszającą przerysowanie przez okno całego
swojego obszaru roboczego.
.IF MouseClick INVOKE lstrlen, ADDR AppName INVOKE TextOut, hdc, hitpoint.x, hitpoint.y,\ ADDR AppName, eax .ENDIF
Kod malujący w sekcji WM_PAINT musi sprawdzić,
czy MouseClick ma wartość
TRUE, ponieważ gdy zostało utworzone okno, system
wysłał wiadomość WM_PAINT, a w tym czasie nie
było jeszcze kliknięć myszką, więc na obszarze roboczym nie powinien
pojawiać się żaden napis. Inicjujemy MouseClick
na
FALSE i zmieniamy tę wartość na TRUE,
gdy pojawi się rzeczywiste kliknięcie lewego przycisku myszki.
Jeśli zdarzyło się przynajmniej jedno kliknięcie myszką, kod rysuje napis na obszarze roboczym okna na pozycji kursora myszki. Zwróć uwagę, iż wywołuje on funkcję lstrlen do obliczenia długości tekstu do wyświetlenia i przesyła tę długość jako ostatni parametr (eax) funkcji TextOut.
Ta sama aplikacja w
Pascalu:
{******************************** ** I Liceum Ogólnokształcące ** ** w Tarnowie ** ** mgr Jerzy Wałaszek ** ********************************} program Mouse; uses Windows; const AppName = 'Nasze pierwsze okno'; var MouseClick : boolean; //false = nie było jeszcze kliknięcia myszką hitpoint : POINT; function WndProc(h:HWND;uMsg:UINT;wP:WPARAM;lP:LPARAM) : longint; var HDevCnt: HDC; ps : PAINTSTRUCT; begin WndProc := 0; case uMsg of WM_DESTROY: PostQuitMessage(0); WM_LBUTTONDOWN : begin hitpoint.x := lP and $ffff; hitpoint.y := (lP shr 16); MouseClick := true; InvalidateRect(h,0,true); end; WM_PAINT : begin HDevCnt := BeginPaint(h,ps); if MouseClick then TextOut(HDevCnt,hitpoint.x,hitpoint.y, AppName,lstrlen(AppName)); EndPaint(h,ps); end; else WndProc := DefWindowProc(h,uMsg,wP,lP); end; end; function WinMain(hI,hPI:HINST;CmdLine:LPSTR;cmdShow:longint) : longint; const ClassName = 'SimpleWinClass'; var wc : WndClassEx; ms : msg; h : HWnd; begin wc.cbSize := SizeOf(WndClassEx); wc.style := CS_HREDRAW or CS_VREDRAW; wc.lpfnWndProc := @WndProc; wc.cbClsExtra := 0; wc.cbWndExtra := 0; wc.hInstance := hI; wc.hbrBackground := COLOR_WINDOW + 1; wc.lpszMenuName := 0; wc.lpszClassName := ClassName; wc.hIcon := LoadIcon(0,IDI_APPLICATION); wc.hIconSm := wc.hIcon; wc.hCursor := LoadCursor(0,IDC_ARROW); RegisterClassEx(wc); h := CreateWindowEx(0,ClassName,AppName, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,0,0,hI,0); ShowWindow(h,CmdShow); UpdateWindow(h); while GetMessage(ms,0,0,0) do begin TranslateMessage(ms); DispatchMessage(ms); end; WinMain := ms.wParam; end; begin MouseClick := false; ExitProcess(WinMain(GetModuleHandle(0),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