Delphi/Canvas, czyli rysowanie

CanvasEdytuj

Załóżmy, że Twój program ma nie tylko wyświetlać standardowe kontrolki Windows, ale także coś rysować. Samo rysowanie w Windows jest zadaniem dość kłopotliwym, ale Delphi dostarcza Ci do niektórych komponentów obiekt o nazwie Canvas ("płótno"). Rysując na obiekcie Canvas danego komponentu w rzeczywistości rysujesz na nim samym. Nie wszystkie komponenty mają swoje płótno.

Najprostszym komponentem z właściwością Canvas jest formularz. Utwórz nowy projekt i dodaj do niego przycisk (Button1). Po wciśnięciu przycisku program ma narysować coś na formularzu.

Jak już wiesz, zareagowanie na kliknięcie przycisku odbywa się w metodzie OnClick.

Obiekt Canvas ma szereg instrukcji służących do rysowania elementów graficznych. Narysujmy koło:

procedure TForm1.Button1Click(Sender: TObject);
begin
Canvas.Ellipse(20,20,80,80);
end;

Uruchom program i sprawdź, jak działa.

Metoda Ellipse rysuje elipsę wewnątrz prostokąta o podanych współrzędnych. Spróbujmy narysować elipsę na cały formularz:

procedure TForm1.Button1Click(Sender: TObject);
begin
Canvas.Ellipse(0,0,Width,Height);
end;

Właściwości Width i Height to szerokość i wysokość formularza. Jeśli uruchomisz program, to zauważysz, że elipsa jest nieco przycięta od dołu (a także z prawej strony). Odpowiada za to pasek tytułowy formularza: samo płótno jest mniejsze od formularza. Niestety, nie wiemy, jak wysoki jest pasek tytułowy okna (na każdym komputerze zależy to od indywidualnych ustawień użytkownika). Sam obiekt Canvas jest dowolnego rozmiaru – możesz rysować nawet poza widoczną częścią okna. Na szczęście, formularz ma także właściwości ClientWidth i ClientHeight. Odpowiadają one za wymiary widocznej i dostępnej części okna. Zmodyfikuj program używając tych dwóch właściwości:

Canvas.Ellipse(0,0,ClientWidth,ClientHeight);

Teraz cała elipsa jest widoczna na ekranie.

Spróbuj teraz zmienić rozmiary swojego okna: najpierw zmniejsz je, a potem zwiększ. Możesz również zminimalizować i przywrócić okno. Co się stało? Część elipsy została utracona. Czemu?

W pewnym momencie system Windows stwierdza, że okno musi zostać przerysowane (narysowane na nowo). Przerysowaniem wszystkich komponentów zajmuje się ich rodzic, a więc przycisk jest przerysowany automatycznie. Jednak po każdej takiej operacji niewidoczna część płótna jest bezpowrotnie tracona. Jak można odzyskać narysowaną elipsę?

Kiedy system domaga się przerysowania okna, wysyła do niego komunikat WM_PAINT. Nie wnikajmy na razie, czym jest WM_PAINT. Dla nas istotne jest, że ten komunikat wywołuje na formularzu zdarzenie OnPaint. Wewnątrz metody obsługującej to zdarzenie możemy przerysować nasze okno.

Wybierz formularz i znajdź jego metodę OnPaint. Dla uproszczenia, usuń przycisk Button1 i przypisaną mu metodę Button1Click. Teraz nadpiszemy metodę OnPaint:

procedure TForm1.FormPaint(Sender: TObject);
begin
Canvas.Ellipse(0,0,ClientWidth,ClientHeight);
end;

Uruchom program, zminimalizuj i zmaksymalizuj go. Zawartość okna nie została utracona (w rzeczywistości, została utracona, ale przywrócenie okna do widoku spowodowało narysowanie jego zawartości na nowo). Teraz pobaw się zmianą rozmiaru okna... Czy coś jest nie tak?

Zmiana rozmiaru okna powoduje wywołanie komunikatu żądania przerysowania okna, ale dla oszczędności, nie całe okno jest przerysowywane, a jedynie ta część, która zostaje odsłonięta przy zwiększaniu rozmiaru. Jak obejść ten problem? Zmiana rozmiaru okna wywołuje zdarzenie OnResize formularza. Wpiszmy więc w tej metodzie:

procedure TForm1.FormResize(Sender: TObject);
begin
Canvas.Ellipse(0,0,ClientWidth,ClientHeight);
end;

Ponieważ metody FormPaint i FormResize w tym konkretnym przypadku mają robić to samo, można skorzystać z zapisu:

procedure TForm1.FormResize(Sender: TObject);
begin
FormPaint(Sender);
end;

Uruchom program i sprawdź, jak zachowuje się rysunek przy zmianie rozmiaru okna.

Prawie dobrze. Przydałoby się jeszcze oczyścić płótno formularza przed narysowaniem, prawda?

procedure TForm1.FormPaint(Sender: TObject);
var
prostokat: TRect; // zmienna pomocnicza, zawierająca współrzędne prostokąta
begin
prostokat:=Rect(0,0,ClientWidth,ClientHeight); // funkcja Rect tworzy prostokąt o zadanych współrzędnych
Canvas.FillRect(prostokat); //wypełnij prostokąt, czyli wyczyść płótno
Canvas.Ellipse(prostokat); //narysuj elipsę wewnątrz prostokąta
end;

Teraz program działa prawidłowo również przy zmienianiu jego rozmiarów. Więcej na temat typu TRect i funkcji Rect znajdziesz w pomocy do Delphi, tutaj omówimy tylko metodę FillRect.

FillRect wypełnia zadany prostokąt aktualnym pędzlem. W naszym przypadku pędzel jest koloru tła formularza. Czym jest pędzel?

PędzelEdytuj

Pędzel (Brush) jest obiektem znajdującym się wewnątrz każdego płótna (Canvas). Pędzel ma szereg właściwości; służy do określenia tekstury, jaką będą wypełniane obiekty. Teksturą może być albo bitmapa, albo jedna ze standardowych tekstur (zobacz w pliku pomocy pod hasłem TBrush.Style). Pędzel ma również swój kolor.

PióroEdytuj

Pióro (Pen) zawiera informacje o wyglądzie pióra na danym płótnie. Pióro ma kolor (Color), grubość (Width) oraz tryb (Mode). Dokładniejsze informacje znajdziesz w Pomocy.

Spróbujmy narysować drugą elipsę innym piórem, a także zastosować biały pędzel:

procedure TForm1.FormPaint(Sender: TObject);
var
prostokat1, prostokat2: TRect;
begin
prostokat1:=Rect(0,0,ClientWidth,ClientHeight);
Canvas.Brush.Color:=clWhite; // clWhite to stała odpowiadająca za kolor biały
Canvas.FillRect(prostokat1); // czyszczenie płótna
// rysujemy pierwszą elipsę
Canvas.Pen.Width:=2;
Canvas.Pen.Color:=clRed; // clRed jest stałą odpowiadającą za kolor czerwony
Canvas.Ellipse(prostokat1);
// rysujemy drugą elipsę
prostokat2:=Rect(10,10,ClientWidth-10,ClientHeight-10);
Canvas.Pen.Width:=1;
Canvas.Pen.Color:=clBlue; // clBlue jest stałą odpowiadajcą za kolor niebieski
Canvas.Ellipse(prostokat2);
end;

Zapamiętaj, że pióro odpowiada za rysowanie linii, a pędzel - za wypełnienia.

Pojedyncze punkty możesz obsługiwać za pomocą właściwości Pixels płótna. Właściwość ta jest tablicą, wymagającą podania dwóch współrzędnych X i Y. Odczytywanie jej daje w wyniku kolor danego punktu, zaś zapisywanie – ustawia zadanemu punktowi odpowiedni kolor.

Zadanie: narysuj na formularzu wypełniony białym kolorem prostokąt (o stałych wymiarach) o niebieskim brzegu szerokości 2 pixeli. Podpowiedź: pusty prostokąt rysuje metoda FrameRect, wypełniony prostokąt bez brzegu – FillRect, zaś wypełniony prostokąt z brzegiem – Rectangle.

(rozwiązanie)


« Poprzednia lekcjaSpis treściNastępna lekcja »