Prawo Greshama - z nieważnymi sprawami czasem dajemy sobie radę, ważne sprawy nigdy nie są rozwiązywane.
Część 4.2. Rysowanie
Czcionki  |   Kolory  |   Elementy graficzne  |   Pliki z grafiką

Czcionki

Jak zapewne zauważyłeś w poprzedniej części, wszystko co ma być wyświetlone w applecie odbywa się za pomocą metod graficznych: również tekst jest "rysowany" a nie "pisany", jak to robiliśmy dotychczas w aplikacjach uruchamianych z wiersza poleceń. Metoda graficzna służąca do wyświetlania tekstów w applecie ma następującą składnię:

	g.drawString ( String WyświetlanyTekst, int x, int y );
gdzie:
	WyświetlanyTekst - to wyrażenie, które ma być wyświetlone;
	x - współrzędna X od, której zaczyna się wyświetlanie;
	y - współrzędna Y od, której zaczyna się wyświetlanie.

Skoro już zaczęliśmy o współrzędnych wyświetlania, to zobaczmy jak w applecie są one liczone. Górny lewy narożnik appletu ma współrzędne (0, 0). Od niego w prawo rośnie wartość współrzędnej X, a w dół - współrzędnej Y. Współrzędne prawego dolnego rogu appletu wynoszą (getSize().width, getSize().height). Wartość tych współrzędnych oznacza jednocześnie odpowiednio: szerokość i wysokość appletu. Poniższy rysunek pokazuje układ współrzędnych appletu:

Współrzędne appletu

wyświetlając napisy w applecie możemy - poza miejscem ich wyświetlenia - określić także krój, typ i wielkość czcionki używanej do wyświetlania: służy do tego klasa Font. Deklaracja czcionek wygląda następująco:

	Font czcionka = new Font ( String NazwaKroju, int typ, int wielkość );
gdzie:
	NazwaKroju - to nazwa czcionki, które ma być użyta do wyświetlania;
	typ - określa krój czcionki; podajemy go jako stałą lub sumę stałych:
		- Font.PLAIN  - czcionka standardowa;
		- Font.BOLD   - czcionka pogrubiona;
		- Font.ITALIC - czcionka pochyła;
	wielkość - wielkość czcionki podana w pikselach.

Należy pamiętać, że wyświetlanie określoną czcionką obowiązuje od momentu jej ustawienia do następnego zdefiniowania kroju czcionki. Zobaczmy na prostym przykładzie jak to działa.

import java.applet.*;
import java.awt.*;

public class Czcionka extends Applet
{  Font f;
   int typ = Font.BOLD + Font.ITALIC;
   int wielkosc = 16;
   String nazwa = "Courier";

   public void init ()
   { repaint();			// metoda "przerysowująca" applet
   }

   public void paint (Graphics g)
   {  f = new Font (nazwa, typ, wielkosc);
      g.setFont (f);
      g.drawString ("Ustawienia czcionki:",   20, 30);
      g.drawString (" nazwa:    " + nazwa,    20, 50);
      g.drawString (" wielkość: " + wielkosc, 20, 70);
      g.drawString (" typ:      " + typ,      20, 90);
   }
}

A oto nasz applet umieszczony na stronie:

Przygotujmy applet prezentujący standardowe czcionki Javy we wszystkich możliwych typach:

import java.applet.*;
import java.awt.*;

public class Czcionki extends Applet
{   public void init ()
   {   repaint();              // metoda "przerysowująca" applet
   }

   public void paint (Graphics g)
   {   Font f;
       String fName[] = new String [6];  // tablica nazw czcionek
       int fType[]    = new int [4];     // tablica krojów czcionek

       fType[0] = Font.PLAIN;
       fType[1] = Font.BOLD;
       fType[2] = Font.ITALIC;
       fType[3] = Font.BOLD + Font.ITALIC;

       fName[0] = "Dialog";
       fName[1] = "DialogInput";
       fName[2] = "Courier";
       fName[3] = "Helvetica";
       fName[4] = "TimesRoman";
       fName[5] = "ZapfDingBats";

       for (int i=0 ; i<6 ; i++)
          for (int j=0 ; j<4 ; j++)
          {   f = new Font (fName[i], fType[j], 12);
              g.setFont (f);          // zmiana używanej czcionki
              g.drawString ("Czcionka: " + fName[i] + ", typ: " + 
                                         fType[j], 20, (i * 4 + j) * 15 + 15);
          }
   }
}

Applet umieszczony na stronie będzie wygladał tak:

Spróbuj teraz samodzielnie napisać aplet, który wyświetli wybraną czcionke w wielkościach od 10 do 60 pikseli z wielkościami pośrednimi co 10 pikseli.

Kolory

Dotychczasowe applety pracowały z domyślnym tłem i kolorem wyświetlania. Java daje jednak możliwość ustawienia praktycznie dowolnego koloru. Możemy to robić na 2 sposoby:
  • korzystając ze stałych Color.nazwa definiujących kilkanaście podstawowych kolorów, gdzie nazwa jest angielską nazwą wybranego koloru (red, blue, green, black, white, itd.) lub
     
  • mieszając kolory czerwony, zielony i niebieski w celu otrzymania pożądanego koloru; każdy z kolorów może przybierać wartość z zakresu od 0 do 255, a składnia definicji koloru ma następującą postać:
    Color c = new Color(int czerwony, int zielony, int niebieski);

     

Aby zilustrować działanie kolorów w Javie przygotujemy applet, który będzie wyświetlał dwie kolumny czcionek: Do wyświetlania pierwszej kolumny użyjemy kolorów predefiniowanych, a czcionki w drugiej kolumnie będą wyświetlane w losowo dobranym kolorze.

import java.applet.*;
import java.awt.*;

public class Kolory extends Applet
{   public void init ()
   {   repaint();			// metoda "przerysowująca" applet
   }

   public void paint (Graphics g)
   {   // wyświetlanie w kolorach predefiniowanych
       g.setFont (new Font ("Courier", Font.BOLD, 14));
       g.drawString ("Zdefiniowanw kolory:", 20, 16);
       g.setColor(Color.black);
                     //ustawienie koloru rysowania
       g.drawString ("Czarny", 20, 36);  // wyświetlenie tekstu
       g.setColor(Color.white);
       g.drawString ("Biały", 20, 56);
       g.setColor(Color.red);
       g.drawString ("Czerwony", 20, 76);
       g.setColor(Color.green);
       g.drawString ("Zielony", 20, 96);
       g.setColor(Color.yellow);
       g.drawString ("Żółty", 20, 116);
       g.setColor(Color.blue);
       g.drawString ("Niebieski", 20, 136);

       // wyświetlanie w kolorach losowych
       g.drawString ("Losowe kolory:", 220, 16);
       for (int i=0 ; i<6 ; i++)
       {   //ustawienie losowego koloru rysowania
           g.setColor(new Color( (int)(Math.random()*255),
                                 (int)(Math.random()*255),
                                 (int)(Math.random()*255)));
           g.drawString ("Kolor losowy: " , 220, i* 20+36);
       }
   }
}

Uruchomiony na stronie WWW applet będzie wyglądał tak:

Przy odświeżaniu strony lewa kolumna będzie zawsze wyglądała tak samo. Prawa kolumna powinna mieć po każdym odświeżeniu inne kolory czcionek, gdyż są one każdorazowo generowane od nowa.

Ustawienie koloru obowiązują podobne zasady, jak ustawienie czcionki: zdefiniowany kolor służy do wyświetlania napisów i elementów graficznych od momentu jego zdefiniowania do kolejnej zmiany koloru. Elementy już wyświetlone nigdy nie ulegają zmianie.

Elementy graficzne

Dotychczas zajmowaliśmy się jedynie wyświetlaniem tekstów. Pora urozmaicić nasz applet o elementy graficzne. W tej części zobaczysz, jak na applecie rysować linie, prostokąty, koła lub elipsy i wielokąty.

Zacznijmy od najprostszego elementu graficznego czyli od rysowania linii prostej. Metoda służąca do rysowania prostej ma następującą składnię:

	g.drawLine ( int x1, int y1, int x2, int y2 );
gdzie:
	x1, y1 - współrzędne punktu, od którego zaczynamy kreślić linię;
	x2, y2 - współrzędne punktu, na którym kończymy kreślić linię.

Linia zawsze rysowana jest w aktualnie ustawionym kolorze.

Żeby sprawdzić, jak można rysować linie, przygotujemy applet, który wyrysuje nam kratkę:

import java.applet.*;
import java.awt.*;

public class Linie extends Applet
{	public void init ()
	{ repaint();			// metoda "przerysowująca" applet
	}

	public void paint (Graphics g)
	{	g.drawString ("Linie:", 10, 15);

		// rysowanie linii poziomych
		for (int i = 20 ; i < getSize().height ; i += 20)
			g.drawLine(10 , i, getSize().width-10, i);

		// rysowanie linii pionowych
		for (int i = 10 ; i < getSize().width ; i += 20)
			g.drawLine(i, 20, i, getSize().height-10);
	}
}

Kolejnym elementem graficznym jest prostokąt. Java umożliwia rysowanie tylko boków prostokątów, z wnętrzem wypełnionym aktualnym kolorem tła lub rysowania wypełnionych prostokątów. W każdym przypadku rysowanie odbywa się w aktualnie zdefiniowanym kolorze. Składnia metod rysujących prostokąty (kwadraty) wygląda następująco:

	g.drawRect ( int x, int y, int szerokość, int wysokość );
	g.fillRect ( int x, int y, int szerokość, int wysokość );
gdzie:
	x, y      - współrzędne lewego górnego rogu prostokąta;
	szerokość - szerokość prostokąta w pikselach;
	wysokość  - wysokość prostokąta w pikselach.

Użycie tych metod ilustruje kolejny applet, rysujący koncentryczne prostokąty. Pamiętać należy, aby rysowanie wypełnionych figur wykonać w odpowiedniej kolejność, ponieważ każda kolejna figura rysowana jest na poprzedniej i może się tak zdarzyć, że ją całkowicie zasłoni. W naszym przykładzie rysujemy prostokąty od największego do najmniejszego. Odwrócenie tej kolejności spowodowałoby, że widać byłoby tylko największy prostokąt, a reszta byłaby niewidoczna.

import java.applet.*;
import java.awt.*;

public class Kwadraty extends Applet
{	public void init ()
	{ repaint();			// metoda "przerysowująca" applet
	}

	public void paint (Graphics g)
	{	int x = 10;
		int y = 20;

		// rysowanie czerwonej ramki wokół appletu
		g.setColor(Color.red);
		g.drawRect(0, 0, getSize().width-1, getSize().height-1);
		g.drawString ("Prostokąty:", 10, 15);

		// rysowanie wypełnionych prostokątów w losowym kolorze
		// zaczynamy od największego a kończymy na najmniejszym
		for (int i=getSize().width-20 ; i>0 ; i-=20, x+=10, y+=10)
		{	g.setColor(new Color((int)(Math.random()*255),
                                               (int)(Math.random()*255),
                                               (int)(Math.random()*255)));
			g.fillRect(x, y, i, i);
		}
	}
}

Kolejnym elementem graficznym jest koło (elipsa). Można rysować tylko okrąg lub elipsę, z wnętrzem wypełnionym aktualnym kolorem tła lub wypełnić je aktualnie zdefiniowanym kolorem. Rysowanie owali w Javie jest dość nietypowe: nie podajemy współrzędnych środka i promienia, ale definiujemy prostokąt, we wnętrzu którego ma znaleźć się kreślona figura. Składnia metod rysujących koło (elipsę) wygląda następująco:

	g.drawOval ( int x, int y, int szerokość, int wysokość );
	g.fillOval ( int x, int y, int szerokość, int wysokość );
gdzie:
	x, y      - współrzędne lewego górnego rogu prostokąta;
	szerokość - szerokość prostokąta w pikselach;
	wysokość  - wysokość prostokąta w pikselach.

Kolejny applet jest niemal identyczny z poprzednim (dotyczą go oczywiście te same uwagi o kolorach i kolejności rysowania). Jedyną modyfikacją jest zmiana używanych do kreślenia metod.

import java.applet.*;
import java.awt.*;

public class Kola extends Applet
{	public void init ()
	{ repaint();			// metoda "przerysowująca" applet
	}

	public void paint (Graphics g)
	{	int x = 10;
		int y = 20;

		// rysowanie czerwonej ramki wokół appletu
		g.setColor(Color.red);
		g.drawRect(0, 0, getSize().width-1, getSize().height-1);
		g.drawString ("Koła:", 10, 15);

		// rysowanie wypełnionych kół w losowym kolorze
		// zaczynamy od największego a kończymy na najmniejszym
		for (int i=getSize().width-20 ; i>0 ; i-=20, x+=10, y+=10)
		{	g.setColor(new Color((int)(Math.random()*255),
                                               (int)(Math.random()*255),
                                               (int)(Math.random()*255)));
			g.fillOval(x, y, i, i);
		}
	}
}

Nieco bardziej skomplikowane jest rysowanie wielokątów. Składnia jest dość podobna do dotychczas poznanych:

	g.drawPolygon ( Polygon f );
	g.fillPolygon ( Polygon f );

Argumentem metody musi być obiekt klasy Polygon. Konstruktor tej z kolei klasy ma następująca składnię:

	g.Polygon ( int wspX [ ], int wspY [ ], int wierzchołków );
gdzie:
	wspX [ ] - tablica zawierająca kolejne współrzędne X 
                         wierzchołków figury w pikselach;
	wspY [ ] - tablica zawierająca kolejne współrzędne Y 
	                     wierzchołków figury w pikselach;
	wierzchołków  - ilość wierzchołków.

Tablice wspX i wspY muszą posiadać dokładnie tyle elementów, ile figura ma wierzchołków. Brzmi to bardzo mądrze i skomplikowanie, ale rzeczywistość nie jest aż tak straszna. Żeby oswoić się z tym problemem przygotujemy kolejny applet: będzie on wyświetlał koncentrycznie trójkąty.

import java.applet.*;
import java.awt.*;

public class Trojkaty extends Applet
{   public void init ()
   {   repaint();            // metoda "przerysowująca" applet
   }

   public void paint (Graphics g)
   {   int x[] = {getSize().width/2, 10, getSize().width-10};
                          // współrzędne X wierzchołków trójkąta
       int y[] = {20, getSize().height-10, getSize().height-10};
                          // współrzędne Y wierzchołków trójkąta
       Polygon p;

       // rysowanie czerwonej ramki wokół appletu
       g.setColor(Color.red);
       g.drawRect(0, 0, getSize().width-1, getSize().height-1);
       g.drawString ("Trójkąty:", 10, 15);

       while (y[0] < getSize().height / 2)
       {   g.setColor(new Color((int)(Math.random()*255),
                                (int)(Math.random()*255),
                                (int)(Math.random()*255)));
           p = new Polygon(x, y, 3);
           g.drawPolygon(p);
                // zamiast 2 powyższych wierszy można osiągnąć ten sam efekt używając
                // takiej składni g.drawPolygon(x, y, 3);
           x[1] += 10;            // zmiana współrzędnych wierzchołków trójkąta
           x[2] -= 10;
           y[0] += 10;
           y[1] -= 10;
           y[2] -= 10;
       }
   }
}

Za pomocą przedstawionych tu metod można w applecie wykonać praktycznie każdy rysunek czy wykres. W przykładach zobaczysz bardziej rozbudowane applety, które mają praktyczne zastosowanie.

Napisz teraz samodzielnie aplet wyświetlający kwadrat z przekatnymi oraz wpisane w niego koło, a w koło z kolei - trójkąt.

Pliki z grafiką

Na zakończenie tej części jeszcze jedno zagadnienie: wstawianie do appletu plików graficznych. Standardowe metody Javy umożliwiają wstawianie zawartości plików typu gif (statycznych i animowanych) i jpg. Wstawianie innych formatów grafiki wymaga opracowania własnych metod ich importu.

Wyświetlenie gotowej grafiki w applecie wymaga wykonania kolejno dwóch czynności:

  • załadowania zawartości pliku graficznego do obiektu klasy Image;
     
  • wyświetlenia tak utworzonego obiektu metodą drawImage clasy Grapgics.
     

Najprostszą metodą załadowania obrazka do pamięci jest użycie metody getImage:

	Image obrazek = getImage( String url, String plik );
gdzie:
    url  - adres, skąd ma być wczytany obrazek: najczęściej będzie to ten sam adres,
           co adres kodu appletu: możemy wtedy użyć metody getDocumentBase();
    plik - nazwa pliku z grafiką.

Po wczytaniu plik znajduje się w pamięci, ale jest niewidoczny. Musimy go wyświetlić metodą drawImage o następującej składni:

	drawImage (Image obrazek, int x, int y, ImageObserver obiekt );
gdzie:
    obrazek - obiekt klasy Image, który ma być wyświetlony;
    x, y    - współrzędne wewnątrz obiektu, od których zaczyna się wyświetlanie grafiki;
    obiekt  - obiekt, w którym grafika ma być wyświetlona; najczęściej będzie to this
              oznaczające bieżący applet.

A oto przykład prostego appletu wyświetlającego obrazek:

import java.applet.*;
import java.awt.*;
import java.awt.image.*;

public class Obrazek1 extends Applet
{	Image obrazek;

	public void init ()
	{ obrazek = getImage(getDocumentBase(), "kubus.gif");
	  repaint();			// metoda "przerysowująca" applet
	}

	public void paint (Graphics g)
	{	g.drawImage (obrazek, 0, 0, this);
	}
}

Na zakończenie tej części o jeszcze jednej metodzie tworzenia grafiki w appletach: tworzenie obiektu klasy Image bezpośrednio w pamięci, bez wczytywania pliku graficznego z dysku. Możemy posłużyć się w tym celu metodą createImage(), która jest zdefiniowana w klasie Applet.

import java.applet.*;
import java.awt.*;
import java.awt.image.*;

public class Obrazek2 extends Applet
{   Image obrazek;

   public void init ()
   {   zbudujObrazek();
       repaint();			// metoda "przerysowująca" applet
   }

   public void paint (Graphics g)
   {   g.drawImage (obrazek, 0, 0, this);
   }

   public void zbudujObrazek()
   {   int szerokosc = 255, wysokosc = 255;
       int pixele[] = new int[255 * 255];
       int x = 0;

       // tworzymy tablicę definiującą kolor każdego punktu obrazka
       for (int i = 0; i < 255; i++)
          for (int j = 0; j < 255; j++)
             pixele[x++] = (255 << 24) | (j << 16) | i;

       // tworzymy obiekt Image o wymiarach 255x255 na podstaw tablicy pixele
       obrazek = createImage(new MemoryImageSource
                         (szerokosc, wysokosc, pixele, 0, szerokosc));
   }
}

I dość ciekawy efekt działania tego appletu:

« wstecz   dalej »