LEKCJA 47: APLIKACJA OBIEKTOWA - RYSOWANIE W OKNIE. ________________________________________________________________ W trakcie tej lekcji opracujemy obiektow� aplikacj� pso�uguj�c si� bibliotek� klas Object Windows Library. ________________________________________________________________ Zaczniemy oczywi�cie od standardowych "klock�w". Definicja klasy Nasza_Aplikacja i modu� prezentacyjno - uruchomieniowy b�d� wygl�da� standardowo, nie musimy im zatem po�wi�ca� zbytniej uwagi. Przytoczymy je jedynie. Pointer do napisu inicjujemy po to, by okienko komunikatu zawiera�o jak�� bardziej konkretn� informacj� dla u�ytkownika. Rysunki z wn�trza tej aplikacji mo�na przy pomocy Schowka przenie�� jako pliki .CLP, b�d� za pomoc� PAINTBRUSH - jako .BMP, .PCX i drukowa�. #include <owl.h> LPSTR Ptr = "Jesli chcesz zapamietac rysunek, \ powinienes przeniesc go do Clipboard'u \ klawiszami [Print Screen] \ lub [Alt]+[PrtScr]."; class TNAplikacja : public TApplication { public: TNAplikacja(LPSTR AName, HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) : TApplication(AName, hInstance, hPrevInstance, lpCmdLine, nCmdShow) {}; virtual void InitMainWindow(); }; ... int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { TNAplikacja OBIEKT("Rysownik. Prawy klawisz umozliwia wyjscie.", hInstance, hPrevInstance, lpCmdLine, nCmdShow); OBIEKT.Run(); return (OBIEKT.Status); } Nic specjalnie ciekawego nie dzieje si� w funkcji inicjuj�cej g��wne okno, ani w funkcji zamykaj�cej aplikacj�. Zmieni�y si� tylko napisy w okienku komunikat�w. void TNAplikacja::InitMainWindow() { MainWindow = new TGOkno(0, Name); } BOOL TGOkno::CanClose() { return (MessageBox(HWindow, Ptr, "KONIEC", MB_YESNO | MB_ICONQUESTION) == IDYES); } Zajmiemy si� teraz g��wn� "maszyneri�" programu. Rozbudujemy obs�ug� komunikat�w przez handlery zaimplenmentowane w klasie G��wne_Okno. _CLASSDEF(TGOkno) class TGOkno : public TWindow { public: HDC dc; BOOL ButtonDown; BOOL Flaga_Start; TGOkno(PTWindowsObject AParent, LPSTR ATitle); //Konstruktor virtual void WMLButtonDown(RTMessage Msg) = [WM_FIRST + WM_LBUTTONDOWN]; virtual void WMLButtonUp(RTMessage Msg) = [WM_FIRST + WM_LBUTTONUP]; virtual void WMMouseMove(RTMessage Msg) = [WM_FIRST + WM_MOUSEMOVE]; virtual void WMRButtonDown(RTMessage Msg) = [WM_FIRST + WM_RBUTTONDOWN]; virtual BOOL CanClose(); }; Konstruktor przekazuje parametry do konstruktora klasy bazowej i zeruje flag� ButtonDown - lewy klawisz myszki przyci�ni�ty. TGOkno::TGOkno(PTWindowsObject AParent, LPSTR ATitle) : TWindow(AParent, ATitle) { ButtonDown = FALSE; } Funkcja obs�uguj�ca zdarzenie WM_LBUTTONDOWN jeden raz inicjuje obs�ug� myszki i ustawia flag�. Funkcje SetCapture() i GetDC() za�atwij� problem relacji kontekstowych i okre�laj� obszar roboczy (client area). Je�li umie�cimy te funkcje w konstruktorze za obszar client area uznany zostanie ca�y ekran. Po zadzia�aniu tych funkcji komunikaty od myszki b�d� dotyczy� wy��cznie obszaru roboczego. Do naci�ni�cia prawego klawisza nie b�dzie dost�pu do "ramki" okna. void TGOkno::WMLButtonDown(RTMessage Msg) { if (!Flaga_Start) { Flaga_Start = TRUE; //UWAGA: SetCapture(HWindow); //Jesli zainicjujemy SetCapture() dc = GetDC(HWindow); //w konstruktorze - mamy caly ekran } MoveTo(dc, Msg.LP.Lo, Msg.LP.Hi); ButtonDown = TRUE; } Funkcja MoweTo() powoduje przesuni�cie kursora graficznego do aktualnej pozycji myszki (ju� wzgl�dnej - z uwzgl�dnieniem dc) bez rysowania linii. Flaga ButtnDown zosta�a ustawiona. Rysowanie scedujemy na metod� obs�uguj�c� WM_MOUSEMOVE - przesuni�cie myszki. void TGOkno::WMMouseMove(RTMessage Msg) { if (ButtonDown) LineTo(dc, Msg.LP.Lo, Msg.LP.Hi); } Je�li lewy klawisz jest naci�ni�ty - funkcja LineTo() b�dzie kre�li� lini� do kolejnych punkt�w "�ledz�c" ruch myszki. Je�li u�ytkownik pu�ci lewy klawisz - zerujemy flag� stanu klawisza ButtonDown <== FALSE. void TGOkno::WMLButtonUp(RTMessage) { if (ButtonDown) ButtonDown = FALSE; } Jak ju� nabazgrzemy po ekranie, prawy klawisz umo�liwi nam skasowanie zawarto�ci przy pomocy InvalidateRect(). void TGOkno::WMRButtonDown(RTMessage) { InvalidateRect(HWindow, 0, 1); ReleaseCapture(); ReleaseDC(HWindow, dc); Flaga_Start = FALSE; } Para funkcji ReleaseDC() i ReleaseCapture() pozwala przekaza� komunikaty od myszki do "ramki okna". Dzi�ki temu mo�na po skasowaniu ekranu np. rozwin�� menu systemowe i zako�czy� aplikacj�. A oto program w ca�o�ci. Listing. Odr�czne rysowanie. ________________________________________________________________ #define STRICT #define WIN31 #include <owl.h> LPSTR Ptr = "Jesli chcesz zapamietac rysunek, \ powinienes przeniesc go do Clipboard'u \ klawiszami [Print Screen] \ lub [Alt]+[PrtScr]."; class TNAplikacja : public TApplication { public: TNAplikacja(LPSTR AName, HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) : TApplication(AName, hInstance, hPrevInstance, lpCmdLine, nCmdShow) {}; virtual void InitMainWindow(); }; _CLASSDEF(TMyWindow) class TMyWindow : public TWindow { public: HDC dc; BOOL ButtonDown; BOOL Flaga_Start; TMyWindow(PTWindowsObject AParent, LPSTR ATitle); //Konstruktor virtual void WMLButtonDown(RTMessage Msg) = [WM_FIRST + WM_LBUTTONDOWN]; virtual void WMLButtonUp(RTMessage Msg) = [WM_FIRST + WM_LBUTTONUP]; virtual void WMMouseMove(RTMessage Msg) = [WM_FIRST + WM_MOUSEMOVE]; virtual void WMRButtonDown(RTMessage Msg) = [WM_FIRST + WM_RBUTTONDOWN]; virtual BOOL CanClose(); }; TMyWindow::TMyWindow(PTWindowsObject AParent, LPSTR ATitle) : TWindow(AParent, ATitle) { ButtonDown = FALSE; } void TMyWindow::WMLButtonDown(RTMessage Msg) { if ( !Flaga_Start ) { Flaga_Start = TRUE; //UWAGA: SetCapture(HWindow); //Jesli zainicjujemy SetCapture() dc = GetDC(HWindow); //w konstruktorze - mamy caly ekran } MoveTo(dc, Msg.LP.Lo, Msg.LP.Hi); ButtonDown = TRUE; } void TMyWindow::WMMouseMove(RTMessage Msg) { if ( ButtonDown ) LineTo(dc, Msg.LP.Lo, Msg.LP.Hi); } void TMyWindow::WMLButtonUp(RTMessage) { if (ButtonDown) ButtonDown = FALSE; } void TMyWindow::WMRButtonDown(RTMessage) { InvalidateRect(HWindow, NULL, TRUE); ReleaseCapture(); ReleaseDC(HWindow, dc); Flaga_Start = FALSE; } void TNAplikacja::InitMainWindow() { MainWindow = new TMyWindow(0, Name); } BOOL TMyWindow::CanClose() { return (MessageBox(HWindow, Ptr, "KONIEC", MB_YESNO | MB_ICONQUESTION) == IDYES); } int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { TNAplikacja OBIEKT("Rysownik. Prawy klawisz umozliwia wyjscie.", hInstance, hPrevInstance, lpCmdLine, nCmdShow); OBIEKT.Run(); return (OBIEKT.Status); } ________________________________________________________________
lazarusp22