Programowanie Wizualno-Obiektowe (studia zaoczne - inżynieria komputerowa) Zajęcia z Delphi 5, program 1 Temat: Zadanie: Obsługa grafiki w Delphi, rysowanie na płótnie, obsługa myszki, zapisywanie obrazków do plików, bitmapy pozaekranowe. Program powinien umożliwiać rysowanie na zadanym polu prostych figur i linii. Powinien też umożliwić zapisanie uzyskanej figury w pliku, oraz odczytanie figury z pliku do programu i jej wyświetlenie. 1. Otwieramy nowa aplikację File>NewApplication 2. Zapisujemy projekt przy pomocy File>Save All w katalogu gdzie będzie kompilowany nasz projekt 3. Dodajemy odpowiednie komponenty (nie wszystkie komponenty zostały tu opisane) w kolejności Panel zawierający wybór figury rysowanej na ekranie TRadioGroup (paleta Standard). Pole graficzne/rysunek pozwalające na podgląd wybranego obrysu i wypełnienia oraz ich kolorów dla zadanej figury TShape (paleta Additional). 1
Komponenty pozwalające na wybranie odpowiedniej opcji dotyczącej stylu piórka (obrysu) i stylu pędzelka (wypełnienia) TComboBox (paleta Standard). Etykiety opisujące TLabel (paleta Standard). Przyciski do wyboru koloru obrysu i wypełnienia TButton (paleta Standard). Komponenty wybierające kolor dla obrysu i wypełnienia TColorDialog (paleta Dialogs). Panel na którym będzie znajdowało się pole do rysowania TPanel (paleta Standard) Pole do rysowania figury TPaintBox (paleta System). Komponent wybierający plik do zapisu rysunku TSaveDialog (paleta Dialogs). 4. Napisać procedurę do obsługi przycisków służących do wyboru koloru obramowania i wypełnienia figury rysowanej na ekranie. Do tego wykorzystamy komponent TColorDialog i własności komponentu TShape (Shape.Pen, Shape.Brush) dla obramowania/linii procedure TForm1.Button1Click(Sender: TObject); { najpierw przypiszmy okienku wartość domyślną } ColorDialog1.Color := Ksztalt.Pen.Color; { następnie wywołajmy okienko na ekran } if ColorDialog1.Execute() then { ta instrukcja wykona się tylko wtedy, gdy użytkownik wciśnie w okienku OK } { Przepisanie koloru } Ksztalt.Pen.Color := ColorDialog1.Color; dla wypełnienia kształtu procedure TForm1.Button2Click(Sender: TObject); { najpierw przypiszmy okienku wartość domyślną } ColorDialog1.Color := Ksztalt.Brush.Color; { następnie wywołajmy okienko na ekran } if ColorDialog1.Execute() then { ta instrukcja wykona się tylko wtedy, gdy użytkownik wciśnie w okienku OK } { Przepisanie koloru } Ksztalt.Brush.Color := ColorDialog1.Color; 5. Napisać procedurę do obsługi wyboru rodzaju obramowania i wypełnienia, w tym celu należy obsłużyć zdarzenie OnChange komponentu TComboBox. Wcześniej dla każdego z komponentów TComboBox należy określić ilość opcji do wyboru edytując jego własność Items i napisać nazwy opcji do wyboru. Podczas wyboru opcji należy odnosić się do numeru opcji (opcje są numerowane od 0) wykorzystując własność: ComboBox.ItemIndex styl obramowania/linii 2
procedure TForm1.StylPiorkaChange(Sender: TObject); with Ksztalt.Pen do case StylPiorka.ItemIndex of 0 : Style := pssolid; 1 : Style := psdash; 2 : Style := psdot; 3 : Style := psdashdot; 4 : Style := psdashdotdot; 5 : Style := psclear; 6 : Style := psinsideframe; styl wypełnienia procedure TForm1.StylPedzelkaChange(Sender: TObject); with Ksztalt.Brush do case StylPedzelka.ItemIndex of 0 : Style := bssolid; 1 : Style := bscross; 2 : Style := bsdiagcross; 3 : Style := bsbdiagonal; 4 : Style := bshorizontal; 5 : Style := bsfdiagonal; 6 : Style := bsvertical; 7 : Style := bsclear; 6. Napisać procedurę inicjalizującą nasz program. W tym wypadku obsługujemy zdarzenie OnShow formularza. Wcześniej należy zadeklarować obiekt typu TBitmap w którym będzie przechowywany nasz rysunek i z którego ewentualnie zapisywać się go będzie do pliku, oraz współrzędne punktu (xp,yp) z którego zaczyna się rysowanie danej figury po naciśnięciu w tym miejscu lewego przycisku myszki. deklaracje zmiennych w programie private Tlo : TBitmap; XP, YP: integer; Rysowac : boolean; procedura inicjacyjna procedure TForm1.FormShow(Sender: TObject); { Ustalimy, jaka wartość typu piórka i pędzelka będzie przyjmowana jako domyślna } StylPiorka.ItemIndex:=0; StylPedzelka.ItemIndex:=0; { Tworzenie obiektu pamiętającego nasz rysunek } Tlo:=TBitmap.Create; { ustalenie jego wielkości na odpowiadającą przeznaczonej do rysowania części okna } 3
Tlo.Height := Rysunek.Height; Tlo.Width := Rysunek.Width; 7. Należy napisać własną procedurę która na płótnie (obiekt typu TCanvas) będącym jej argumentem będzie rysowała kształt zdefiniowany punktem początku i punktem końca {(xp,yp),(xk,yk)} deklaracja procedury private... procedure Rysuj(Canvas : TCanvas; xp, yp, xk, yk : integer); treść procedury procedure TForm1.Rysuj(Canvas: TCanvas; xp, yp, xk, yk : integer); { Procedura ta będzie rysowała na płótnie o nazwie Canvas kształt zdefiniowany zmiennymi całkowitymi xp, yp, xk, yk} { Ustawienie pędzelka i piórka } Canvas.Pen:=Ksztalt.Pen; Canvas.Brush:=Ksztalt.Brush; { rysowanie } case Figury.ItemIndex of 0 : Canvas.MoveTo(xp, yp); Canvas.LineTo(xk, yk); 1 : Canvas.Rectangle(xp, yp, xk, yk); 8. Następnie piszemy procedurę służącą do obsługi zdarzeń związanych z myszką, Wykorzystywane zdarzenia to zdarzenia formularza takie jak: - OnMouseDown - naciśnięcie lewego przycisku w określonym punkcie, pozwala wykorzystać współrzędne (X,Y) punktu na który wskazywał kursor, gdy przycisk został wciśnięty. - OnMouseMove - ruch myszki z wciśniętym lewym przyciskiem, zwracana jest informacja o współrzędnych kolejnych punktów na ekranie (X,Y). - OnMouseUp - Puszczenie lewego przycisku myszki, pozwala wykorzystać współrzędne (X,Y) punktu na który wskazywał kursor, gdy przycisk został puszczony. Należy zwrócić uwagę na to jak wykorzystywana jest zmienna logiczna rysować, zadeklarowana na początku programu (pkt.6), mówiąca o tym czy nasz rysunek jest rysowany na ekranie. Ustawiana jest ona na wartość true, w przypadku gdy lewy przycisk myszki został wciśnięty (OnMouseDown). Dopiero wtedy ruszając myszką można cokolwiek narysować na ekranie (OnMouseMove). Zmienna rysowac przyjmuje wartość false, w przypadku puszczenia lewego przycisku (OnMouseUp). Ciekawe jest też rozwiązanie rysowania. Wykorzystywana jest tu funkcja Rysuj która rysuje tymczasową figurę na ekranie, natomiast ostateczną figurę najpierw w obiekcie TBitmap nie 4
pokazywanym na ekranie. Jest to tzw. bitmapa pozaekranowa (ang. offscreen bitmap), Korzystania z bitmap pozaekranowych sprowadza się do trzech zasadniczych zagadnień: Utworzenie bitmapy w pamięci. Wykonanie rysunku w bitmapie pamięciowej. Skopiowanie bitmapy z pamięci na ekran (po zatwierdzeniu wszystkich zmian). Przy każdym tymczasowym narysowaniu zmazywana jest poprzednia zmiana i jest pokazywany ostatni zapisany rysunek z obiektu TBitmap. Do pokazania tego obiektu na ekranie wykorzystywana jest metoda do wyświetlania na określonym płótnie na ekranie (PaintBox.Canvas) całej mapy bitowej (jeśli ma ona rozmiar tego płótna) PaintBox.Canvas.Draw(0,0,Tło:TBitmap). Dopiero po puszczeniu przycisku podczas rysowania zmiany są wprowadzone na stałe. procedure TForm1.RysunekMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); XP:=X; YP:=Y; { Zaznaczenie, że będziemy rysować figurę tymczasową } Rysowac := True; procedure TForm1.RysunekMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); if Rysowac then { Rysujemy bitmapę zawierającą nasz rysunek } Rysunek.Canvas.Draw(0,0,Tlo); { Dodajemy dodatkową figurę, ale nie na bitmapę, tylko na PaintBox } Rysuj(Rysunek.Canvas, XP, YP, X, Y); procedure TForm1.RysunekMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); { Puszczenie przycisku - pora narysować figurę na bitmapie } { rysowanie } if Rysowac then { Dodajemy dodatkową figurę na bitmapę } Rysuj(Tlo.Canvas, XP, YP, X, Y); { Rysujemy bitmapę zawierającą nasz rysunek } Rysunek.Canvas.Draw(0,0,Tlo); { Zaznaczenie, że nie trzeba już rysować figury tymczasowej } Rysowac:=False; 9. Program można uzupełnić o procedury służące do zapisywania i czytania z plików.bmp bitmap. W tym celu wykorzystywane mogą być metody obiektu klasy TBitmap - LoadFromFile(nazwaPliku:string) - SaveToFile(nazwaPliku:string) 5