UNIWERSYTET RZESZOWSKI KATEDRA INFORMATYKI Opracował: mgr inż. Przemysław Pardel, dr hab. Bogdan Kwolek v1.01 2010 Grafika i komunikacja człowiek komputer Laboratorium Część 2: Graphics ZAGADNIENIA DO ZREALIZOWANIA (2H) 1. Rysowanie i wypełnianie obszarów... 2 3.1 Linie... 2 Przykład 1 do zrealizowania... 2 3.2 Prostokąty... 2 Przykład 2 do zrealizowania... 2 Przykład 3 do zrealizowania... 3 3.3 Wielokąty... 4 Przykład 3 do zrealizowania... 5 3.4 Elipsy... 5 Przykład 4 do zrealizowania... 5 3.5 Łuki... 6 Przykład 4 do zrealizowania... 7 Przykład 5 do zrealizowania... 8 3.6 Kopiowanie i usuwanie... 10
1. RYSOWANIE I WYPEŁNIANIE OBSZARÓW Dla wielu rysowanych elementów dostępne są dwa rodzaje metod: metody rysujące, przy użyciu których można nakreślić obrys danego elementu, metody wypełniające, za pomocą których można wypełnić wnętrze danego elementu żądanym kolorem. Obydwa rodzaje metod rysują obrys elementu przy użyciu bieżącego koloru. 3.1 LINIE Do rysowania linii pomiędzy dwoma punktami służy metoda drawline(). Pobiera ona cztery parametry: współrzędne x, y początku linii współrzędne x, y końca linii. Zademonstrowano to na poniższym przykładzie: drawline(x1, y1, x2, y2); Wykonanie powyższego polecenia spowoduje narysowanie linii od punktu o współrzędnych (x1, y1) do punktu o współrzędnych (x2, y2). Szerokość linii jest ustawiona na 1 piksel. PRZYKŁAD 1 DO ZREALIZOWANIA import java.awt.graphics; public class MyLine extends java.applet.applet { public void paint(graphics g) { g.drawline(15,25,65,75); 3.2 PROSTOKĄTY Klasa Graphics udostępnia metody do rysowania prostokątów normalnych" oraz prostokątów z zaokrąglonymi narożnikami. Obydwa rodzaje prostokątów mogą być narysowane jako puste (tylko obrys prostokąta) oraz jako wypełnione żądanym kolorem. Aby narysować normalny" prostokąt, należy użyć metody drawrect() do prostokątów pustych" oraz fillrect() do prostokątów wypełnionych kolorem. Obydwie metody pobierają cztery parametry: współrzędne (x, y) lewego, górnego narożnika prostokąta, szerokość prostokąta, wysokość prostokąta. PRZYKŁAD 2 DO ZREALIZOWANIA
import java.awt.graphics; public class MyRect extends java.applet.applet { public void paint(graphics g) { g.drawrect(20,20,60,60); g.fillrect(120,20,60,60); Prostokąty z zaokrąglonymi narożnikami wymagają użycia metod drawroundrect() lub fillroundrect(). Oprócz czterech parametrów, pobierają one dwa parametry dodatkowe. Określają one wysokość i szerokość obszaru, w którym znajdują się zaokrąglone narożniki. Im większy jest taki obszar, tym bardziej będą zaokrąglone narożniki prostokąta. Dobierając odpowiednio duże obszary zaokrągleń, można nawet spowodować, że prostokąt będzie wyglądał jak okrąg. Na rysunku 1 przedstawiono kilka przykładów prostokątów z zaokrąglonymi narożnikami. W pierwszym przypadku obszar zaokrąglenia ma wymiary 5x5 pikseli, w drugim 30x10 pikseli, a w trzecim 20x20, co powoduje, że ostatni prostokąt wygląda niemal jak okrąg. Rysunek 1: Kilka przykładów prostokątów z zaokrąglonymi narożnikami PRZYKŁAD 3 DO ZREALIZOWANIA import java.awt.graphics; public class MyRRect extends java.applet.applet { public void paint(graphics g) { g.drawroundrect(20,20,60,60,10,10);
g.fillroundrect(120,20,60,60,20,20); 3.3 WIELOKĄTY Wielokąty mogą być rysowane przy użyciu metod drawpolygon() lub fillpolygon(). Aby narysować wielokąt, należy wyznaczyć współrzędne (x, y) każdego jego wierzchołka. Wielokąt może być traktowany jako seria połączonych ze sobą linii. Pierwsza linia jest rysowana od punktu A do punktu B, następnie punkt B staje się początkiem następnej linii itd. Poszczególne współrzędne mogą być podawane na dwa sposoby: jako para tablic liczb całkowitych, z których pierwsza przechowuje współrzędne x, a druga współrzędne y, jako obiekt Polygon, tworzony na podstawie pary tablic liczb całkowitych, z których pierwsza przechowuje współrzędne x, a druga współrzędne y. Drugi z podanych sposobów jest bardziej elastyczny, ponieważ nowe punkty mogą być dodawane do definicji wielokąta, zanim zostanie on narysowany. Aby narysować wielokąt, oprócz współrzędnych x, y poszczególnych wierzchołków należy podać liczbę wierzchołków. Dzięki temu nie będzie możliwe zdefiniowanie większej liczby par współrzędnych niż wierzchołków ani więcej wierzchołków niż par współrzędnych w każdym z tych przypadków kompilator Java wyświetli błąd. Aby utworzyć obiekt Polygon, należy w pierwszej kolejności przy pomocy polecenia new Polygon() utworzyć pusty wielokąt, tak jak w poniższym przykładzie: Polygon poly = new Poligon(); Alternatywnym rozwiązaniem może być utworzenie wielokąta na podstawie serii współrzędnych jego wierzchołków przechowywanych w tablicach liczb całkowitych. Wymaga to wywołania konstruktora Polygon(int[], int[], int), którego parametry to tablica współrzędnych x, tablica współrzędnych y oraz całkowita liczba wierzchołków. Poniżej przedstawiono przykład zastosowania tego konstruktora: int x[] = {10, 20, 30, 40, 50; int y[] = {15, 25, 35, 45, 55; int points = x.length; Polygon poly = new Polygon(x, y, points): Po utworzeniu obiektu Polygon można dodawać do niego nowe wierzchołki poprzez wywołanie na jego rzecz metody addpoint(). Jako parametry pobiera ona współrzędne (x, y) nowego wierzchołka i dodaje je do definicji wielokąta. Zobrazowano to poniżej: poly.addpoint(60, 65);
Po zakończeniu definiowania wierzchołków wielokąta można go narysować wywołując jedną z metod drawpolygon() lub fillpolygon(). Zarówno pierwsza, jak i druga z nich, pobiera tylko jeden parametr, mianowicie obiekt Polygon: comp2d.drawpolygon(poly); Jeżeli używamy metody drawpolygon() to możemy zamknąć wielokąt, podając dla ostatniego wierzchołka takie same współrzędne jak dla wierzchołka pierwszego, w przeciwnym wypadku wielokąt pozostanie otwarty. Metoda fillpolygon() automatycznie domyka rysowany wielokąt bez konieczności jawnego podawania współrzędnych zamykającego wierzchołka. W stosunku do wersji Java 1.0 zachowanie metody drawpolygon() radykalnie się zmieniło. W wersji Java 2 metoda drawpolygon() automatycznie domyka wielokąt w ten sam sposób jak robi to metoda fillpolygon(). Jeżeli chcemy uzyskać wielokąt otwarty, to należy skorzystać z metody drawpolyline(). PRZYKŁAD 3 DO ZREALIZOWANIA import java.awt.graphics; public class MyPoly extends java.applet.applet { public void paint(graphics g) { int exes[] = { 39,94,97,142,53,58,26 ; int whys[] = { 33,74,36,70,108,80,106 ; int pts = exes.length; g.drawpolygon(exes,whys,pts); g.fillpolygon(poly);!!! 3.4 ELIPSY Do rysowaniu elips i okręgów służą metody drawoval() oraz filloval(). Obydwie metody pobierają cztery parametry: współrzędne x, y elipsy, wysokość i szerokość elipsy (inaczej mówiąc średnice elipsy) w przypadku okręgów obydwa parametry mają identyczne wartości. Elipsy są traktowane dokładnie tak samo jak prostokąty. Współrzędne (x, y) odnoszą się do lewego, górnego narożnika obszaru zajmowanego przez elipsę. PRZYKŁAD 4 DO ZREALIZOWANIA import java.awt.graphics; public class MyOval extends java.applet.applet {
public void paint(graphics g) { g.drawoval(20,20,60,60); g.filloval(120,20,100,60); 3.5 ŁUKI Ze wszystkich operacji graficznych to właśnie rysowanie łuków jest najbardziej skomplikowanym zagadnieniem. Łuk jest w zasadzie fragmentem elipsy, stąd w języku Java łuki zostały po prostu zaimplementowane jako częściowo narysowane elipsy. Do rysowania łuków służą metody drawarc() oraz fillarc(), które pobierają sześć parametrów: współrzędne x, y elipsy, wysokość i szerokość elipsy, kąt, od którego rozpoczynamy rysowanie łuku (kąt początkowy), długość" łuku (w stopniach). Pierwsze cztery parametry są identyczne jak w przypadku elips i działają dokładnie w ten sam sposób. Kąt początkowy łuku jest liczony od 0 do 359 w kierunku przeciwnym do ruchu wskazówek zegara. Posługując się skalą godzinową, kąt 0 odpowiada godzinie 3:00; 90 godzinie 12:00; 180 godzinie 9:00, a 270 godzinie 6:00. Długość" łuku jest mierzona od 0 do 359 w kierunku przeciwnym do ruchu wskazówek zegara i od 0 do -359 w kierunku zgodnym z ruchem wskazówek zegara. Rysunek 2 ilustruje sposób wyliczania dwóch ostatnich parametrów. Rysunek 2. Wyliczanie długości łuku Łuki wypełnione są rysowane w ten sposób, jakby były częściami tortu o odpowiednich wymiarach. Zamykanie takiego łuku odbywa się nie przez dorysowanie cięciwy, ale dwóch linii prostych biegnących ze skrajnych punktów łuku do centralnego punktu elipsy, na której łuk jest oparty. Poniżej przedstawiono przykład wywołania metody drawarc(): comp2d.drawarc(20. 25. 315, 150. 5. -190);
Wykonanie powyższego polecenia spowoduje narysowanie łuku w miejscu o współrzędnych 20, 25, długości elipsy 315 pikseli, szerokości elipsy 150 pikseli. Łuk posiada kąt początkowy ustawiony na 5 i długość 190 zgodnie z ruchem wskazówek zegara. PRZYKŁAD 4 DO ZREALIZOWANIA import java.awt.*; public class Lamp extends java.applet.applet { public void paint(graphics g) { g.fillrect(0,250,290,290); g.drawline(125,250,125,160); g.drawline(175,250,175,160); g.drawarc(85,157,130,50,-65,312); g.drawarc(85,87,130,50,62,58); g.drawline(85,177,119,89); g.drawline(215,177,181,89); g.fillarc(78,120,40,40,63,-174); g.filloval(120,96,40,40); g.fillarc(173,100,40,40,110,180); Rysunek 3: Efekt działania klasy Lamp
PRZYKŁAD 5 DO ZREALIZOWANIA import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Map extends JFrame { public Map() { super("map"); setsize(350, 350); ExitWindow exit = new ExitWindow(); MapPane map = new MapPane(); getcontentpane().add(map); addwindowlistener(exit); public static void main(string[] arguments) { Map frame = new Map(); frame.show(); class MapPane extends JPanel { public void paintcomponent(graphics comp) { Graphics2D comp2d = (Graphics2D)comp; comp2d.drawstring("florida", 185, 75); comp2d.drawline(185, 80, 222, 80); comp2d.drawrect(2, 2, 335, 320); comp2d.drawroundrect(182, 61, 43, 24, 10, 8); int x[] = { 10, 234, 253, 261, 333, 326, 295, 259, 205, 211, 195, 191, 120, 94, 81, 12, 10 ; int y[] = {12,15, 25, 71, 209, 278, 310, 274, 188, 171, 174, 118, 56, 68, 49, 37, 12 ;
int pts = x.length; Polygon poly = new Polygon(x, y, pts); comp2d.drawpolygon(poly); comp2d.filloval(235,140,15,15); comp2d.filloval(225,130,15,15); comp2d.filloval(245,130,15,15); for (int ax = 50; ax < 150; ax += 10) for (int ay = 120; ay < 320 ; ay += 10) comp2d.drawarc(ax, ay, 10, 10, 0, -180); class ExitWindow extends WindowAdapter { public void windowclosing(windowevent e) { System.exit(0); Rysunek 4: Aplikacja Map.java
Przedstawiona na rysunku mapa jest znakomitym przykładem wykorzystania możliwości graficznych oferowanych przez metody klasy Graphics. 3.6 KOPIOWANIE I USUWANIE Klasa Graphics udostępnia pewne możliwości typu wytnij-wklej: metoda copyarea() kopiuje prostokątny obszar okna w inne miejsce tego okna, metoda clearrect() kasuje (czyści) prostokątny obszar okna. Metoda copyarea() pobiera sześć argumentów: współrzędne x, y prostokątnego obszaru, który będzie kopiowany, szerokość i wysokość tego obszaru, odległości w pionie oraz w poziomie mierzone w pikselach, które określają przesunięcie kopiowanego obszaru od pozycji początkowej. Poniższe polecenie kopiuje obszar o rozmiarze 100x100 pikseli od miejsca położonego o 50 pikseli na prawo i 25 pikseli w dół od pozycji początkowej. Polecenie to, wykorzystuje obiekt klasy Graphics o nazwie screen: screen.copyarea(0, 0, 100, 100, 50, 25); //zrealizować w przykładzie Map.java (Patrz Rysunek 5) Metoda clearrect() posiada cztery identyczne parametry, podobnie jak to miało miejsce w przypadku metod drawrect() i fillrect(). Wypełnia ona obszar prostokątny, określony podanymi wartościami, bieżącym kolorem tła danego okna. Jeżeli chcemy wyczyścić cały obszar okna, to do określenia jego rozmiarów możemy wykorzystać metodę size(). Zwraca ona obiekt klasy Dimension, którego wartości zmiennych width oraz height reprezentują bieżące rozmiary okna apletu (odpowiednio szerokość i wysokość) i możemy je wykorzystać bezpośrednio w wywołaniu metody clearrect(), tak jak to przedstawiono na poniższym przykładzie: screen.clearrect(0, 0, getsize().width. getsize().height); Rysunek 5: Aplikacja Map.java ze skopiowanym fragmentem