Java i grafika (II)

W poprzednim numerze opisaliśmy szablon aplikacji graficznej w Javie i poznaliśmy zasadę rysowania na komponentach. Przygotowaliśmy też elementy sterujące aplikacji w postaci paska menu. Obecnie zajmiemy się generowaniem grafiki 2D oraz procedurami obsługi zdarzeń.

W poprzednim numerze opisaliśmy szablon aplikacji graficznej w Javie i poznaliśmy zasadę rysowania na komponentach. Przygotowaliśmy też elementy sterujące aplikacji w postaci paska menu. Obecnie zajmiemy się generowaniem grafiki 2D oraz procedurami obsługi zdarzeń.

Aplikacja, której budowę rozpoczęliśmy w zeszłym miesiącu, jest już przygotowana do rysowania na powierzchni swojego głównego panelu. Klasa pochodna panelu zawiera naszą własną implementację metody paintComponent, która najpierw wywołuje oryginalną metodę paintComponent z klasy nadrzędnej, a następnie posługując się klasą Graphics2D, wykonuje różne dodatkowe operacje graficzne, m.in. wypisuje ciągi znaków. Teraz wykorzystamy klasę Graphics2D do rysowania figur geometrycznych.

W pakiecie java.awt.geom jest klasa RectangularShape, od której pochodzą klasy tworzące określone figury geometryczne. Do narysowania figury służy metoda draw() klasy Graphics2D, do której przekazujemy obiekt danej figury. I tak np. klasą odpowiadającą za tworzenie prostokąta jest klasa Rectangle2D.Double, która pobiera cztery parametry w postaci liczb typu double, odpowiednio współrzędne x i y oraz szerokość i wysokość prostokąta.

new Rectangle2D.Double(100,100,250,150);

Za utworzenie elipsy odpowiada inna klasa Ellipse2D.Double, która pobiera te same parametry, co konstruktor klasy prostokąta, tyle że na ich podstawie rysuje nie prostokąt, lecz wpisaną w niego elipsę. Do narysowania kwadratu lub okręgu wykorzystuje się oczywiście te same funkcje z odpowiednimi parametrami.

new Ellipse2D.Double(100,100,150,150);

Do narysowania łuku kąta służy z kolei klasa Arc2D.Double.

new Arc2D.Double(100,100,150,150,0,90,2);

Rysunek 1. Menu wyboru koloru tła panelu jest dołączone bezpośrednio do powierzchni okna.

Rysunek 1. Menu wyboru koloru tła panelu jest dołączone bezpośrednio do powierzchni okna.

Pierwsze cztery parametry są takie same, jak w przypadku prostokąta czy elipsy, natomiast piąty określa miejsce początkowe rysowania łuku kąta w stopniach, a szósty jego długość. Ostatni argument jest liczbą całkowitą, która określa styl łuku, tj. OPEN (0), CHORD (1) lub PIE (2).

Po narysowaniu figury za pomocą metody draw(), możemy ją wypełnić określonym kolorem. W tym celu wywołujemy metodę setPaint() z wybranym kolorem, a następnie metodę fill() przekazując jej obiekt figury, którą chcemy wypełnić.

g2.setPaint(kfigury);

g2.fill(figu);

Wykonujemy te operacje w metodzie namaluj(), która jest wywoływana przez metodę paintComponent() klasy PanelOkna. Po napisaniu kodu odpowiedzialnego za rysowanie, pozostaje jeszcze powiązać go ze zdarzeniem wywoływanym przez użytkownika. Powróćmy zatem do klasy Okno. Jej metoda rysuj() wykorzystuje funkcję addActionListener() do przypisania obiektu typu ActionListener do wskazanego elementu menu rozwijanego.

void rysuj(JMenuItem punk, final String naz

final RectangularShape rs) {

punk.addActionListener(

new ActionListener() {

public void actionPerformed(ActionEvent ev) {

figur = rs;

napis = naz;

repaint();

}

}

);

}

Pierwszy parametr tej metody to element menu rozwijanego, do którego ma zostać przypisana procedura obsługi zdarzenia. Drugi to ciąg znaków zawierający nazwę figury, a trzeci to obiekt typu RectangularShape, czyli konkretny kształt. Wywołanie metody rysuj() powiąże zatem kliknięcie wybranej opcji menu z procedurą obsługi zdarzenia actionPerformed() zdefiniowaną w obiekcie ActionListener.

Jeśli więc z listy menu wybrana zostanie określona figura geometryczna np. prostokąt, wtedy zmiennej figur zostanie przypisany obiekt podany jako trzeci parametr. Jednocześnie zmiennej napis zostanie przypisany ciąg znaków przekazany jako drugi parametr. Wykonana zostanie także instrukcja repaint(), która odmaluje okno. Zmienna figur typu RectangularShape oraz zmienna napis typu String zostały zadeklarowane i zainicjalizowane na początku klasy Okno:

private RectangularShape figur = new Rectangle2D.Double();

private String napis = "";

Wielokrotne wywołanie metody rysuj() z kolejnymi pozycjami menu podawanymi jako pierwszy parametr spowoduje przypisanie każdej opcji menu właściwej procedury obsługi.

rysuj(kwadrat,"Kwadrat"

new Rectangle2D.Double(100,100,150,150));

rysuj(prostokat,"Prostokąt"

new Rectangle2D.Double(100,100,250,150));

rysuj(kolo,"Koło"

new Ellipse2D.Double(100,100,150,150));

...

Teraz przyjrzymy się kolejnej metodzie klasy Okno, metodzie kolor_tla(), która pobiera dwa parametry: obiekt elementu menu rozwijanego oraz obiekt koloru. Ponownie poszczególnym opcjom przypisujemy obiekty ActionListener, które tym razem zmieniają tło panelu PanelOkna oraz oczywiście powodują odmalowanie jego zawartości.

void kolor_tla(JMenuItem punkt, final Color kolo) {

punkt.addActionListener(

new ActionListener() {

public void actionPerformed(ActionEvent ev) {

panel.setBackground(kolo);

repaint();

}

}

);

}

Metodę tę wywołaliśmy dla wszystkich elementów menu rozwijanego.

kolor_tla(zielony, new Color(153,204,153));

kolor_tla(pomaranczowy, new Color(255,204,0));

kolor_tla(blekit, new Color(153,204,255));

kolor_tla(fiolet, new Color(204,195,255));

Po wykonaniu tych instrukcji z każdą opcją menu skojarzona zostanie procedura obsługi ustawiająca nowy kolor i odmalowująca powierzchnię panelu.

Rysunek 2. Gotowa aplikacja.

Rysunek 2. Gotowa aplikacja.

Wszystkie dotychczasowe operacje wykonywaliśmy albo w klasie PanelOkna, albo w konstruktorze klasy Okno. Również dodając opcje menu, nie potrzebowaliśmy samego obiektu klasy PanelOkna, ponieważ pasek menu dodaliśmy bezpośrednio do okna, aby zintegrować go z paskiem tytułu aplikacji. Teraz chcemy jednak dodać do naszego panelu dodatkowe komponenty, musimy zatem w konstruktorze klasy Okno utworzyć obiekt panel klasy PanelOkna.

panel = new PanelOkna();

Pierwszym elementem dodanym do panelu będzie zwykła etykieta:

kolorfigury = new JLabel("Wybierz kolor figury: ");

panel.add(kolorfigury);

Następnie utworzymy listę rozwijaną do wyboru koloru figury. Do tworzenia takich list służy klasa JComboBox. Aby jednak dopasować ją kolorystycznie do pozostałych elementów aplikacji, musimy utworzyć klasę pochodną. Nową klasę Lista umieścimy w katalogu listy:


Zobacz również