![]() |
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