Uniwersytet Łódzki
Wydział Matematyki i Informatyki, Katedra Analizy Nieliniowej
AWT cd..
Java
Wykład 4
Plan wykładu
Manager rozkładu
Zdarzenia w AWT
Grafika 2D w AWT
Omówienie przykładowych pakietów
Wyjątki
Layout Manager
Menadżer rozkładu przypisany jest do każdego kontenera
Ustala pozycję i wielkość dla komponentu w oknie
Pomocny przy organizowaniu zawartości okna, które zmienia rozmiar lub jest wyświetlane na różnych systemach
Prosty dla prostych rozkładów, jednakże bardzo ciężko jest projektować programy zawierające wiele elementów w pojedynczym menadżerze rozkładu.
W celu zarządzania złożonymi rozkładami należy:
Używać zagnieżdżonych kontenerów – każdy z własnym layout manager
Używać niewidzialne komponenty oraz opcji menadżerów rozkładów
Pisać własne layout manager
Wyłączyć niektóre layout manager i zarządzać komponentami manualnie.
Wszystkie Layout Manager implementują Layout Manager Interface
FlowLayout Manager
Domyśłny dla Panel, JPanel, Applet
Zachowanie:
Zmienianie rozmiaru komponentów do ich najlepszego rozmiaru
Umieszczanie komponentów w rzędzie od lewej do prawej od góry do dołu
Wiersze są wyśrodkowane domyślnie
Konstruktor
FlowLayout() – wyśorodkowuje każdy wiersz i utrzymuje 5 px. odstępy pomiędzy komponentami i wierszami
FlowLayout(int alignment) – utrzymuje 5px odstępy w wierszu, ale zmienia wyrównanie w wierszach: FlowLayout.LEFT, FlowLayout.RIGHT,
FlowLayout.CENTER
FlowLayout(int alignment, int hGap, int vGap) – pozwala specyfikować
wyrównanie w wierszach jak i również odstęp poziomy i poionowy pomiędzy komponentami w [px].
BorderLayout Manager
Każdy z komponentów może być włożony do kontenera w jedną z lokalizacji:
North
South
East
West
GridLayout
Zachowanie
Podział okna na równej wielkości prostokąty bazujące na liczbie wierszy i kolumn podanych jako argument.
Komponenty umieszczane są w komórkach w kolejności od lewej do prawej od góry do dołu w porządku dodawania do kontenera
posiadającego ten rozkład
Ignoruje preferowany rozmiar
komponentu. Każdy komponent jest skalowany i dopasowywany do
komórki
Zbyt mała liczba komponentów powoduje pozostawienie wolnego miejsca w postaci białych prostokątów
Zbyt wiele komponentów powoduje nieplanowane dodanie nowych kolumn
GridLayout()
Tworzy pojedynczy wiersz z jedną kolumną zaalokowana dla każdego komponentu.
GridLayout(int rows, int cols)
Dzieli okno zgodnie z podaną liczbą kolumn oraz wierszy
Liczba kolumn lub wierszy może być zero
GridLayout(int rows, int cols, int hGap, int vGap)
Pozwala na wyspecyfikowanie
przestrzeni pomiędzy poszczególnymi komórkami
GridBagLayout
Zachowanie
Dzieli okno na komórki, w których komponenty mogą mieć różne rozmiary
Dużo wygodniejsze i bardziej elastyczne niż inne standardowe menadżerzy rozkładów, jednakże dużo trudniejsze w użyciu:
Każdy komponent zarządzany przez GridBagLayout skojarzony jest z GridBagConstraints, który definiowany jest przez:
jak komponent jest rozkładany w wyświetlanym obszarze
w której komórce komponent się rozpoczyna i kończy
jak komponent rozciąga się, kiedy przestrzeń się zwiększa
wyrównanie w komórkach
Java 5 wprowadziła SpringLayout, który jest podobny jednakże bardziej
Użycie GridBagLayout
Ustawienie rozkładu i zachowanie go w zmiennej referencyjnej:
GridBagLayout layout = new GridBagLayout();
setLayout(layout);
Przygotowanie objektu GridBagConstraints
GridBagConstraints constraints = new GridBagConstraints();
Ustawienie GridBagConstraints dla jednego komponentu:
constraints.gridx = x1;
constraints.gridy = y1;
constraints.gridwidth = width1;
constraints.gridheight = height1;
Dodanie 1 komponentu do okna uwzględniając jego GridBagConstraints
add(component1, constraints);
Powtórzenie kroków dla pozostałych komponentów
Pola w GridBagConstrains
gridx, gridy
Specyfikuje górny lewy róg komponentu
Najwyższa komórka jest lokowana w (gridx, gridy)=(0,0)
Ustawienie GridBagConstraints.RELATIVE w sytuacji autoinkrementacji kolumn wierszy
GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = GridBagConstraints.RELATIVE;
container.add(new Button(„1"), constraints);
Wyłączenie menadżera rozkładu
Zachowanie
Jeśli rozkład jest ustawiony jako null, wówczas komponenty muszą być
rozmieszczane i skalowane ręcznie.
Pozycjonowanie i skalowanie komponentów:
component.setSize(width, height)
component.setLocation(left, top)
lub component.setBounds(left, top,width, height)
Wskazówki przy używaniu Layout Manager
Używaj zagnieżdżonych kontenerów
Nie próbuje dopasować na siłę swojego złożonego rozkładu elementów do jednego menadżera rozkładu. Staraj się podzielić projekt w sekcje.
Skorzystaj z Panel jako sekcji wykorzystując do tego jego własny layout manager
Wyłącz menadżera rozkładu dla niektórych kontenerów, w których nie ma zbyt wielu elementów i można zarządzać nimi ręcznie.
Dopasuj puste miejsce wokół komponentów:
Po przez zmianę rozmiaru przestrzeni przydzielonej standardowo przez menadżera rozkładu
Użyj Płótna lub Box (w Swing) jako niewidzialnych elementów
oddzielających komponenty
Menadżer rozkładu - podsumowanie
Inne rozkłady: BoxLayout, CardLayout
Domyślne layout managers
Dla apletu i panelu: FlowLayout
Dla okienka i dialog BorderLayout
Menadżer rozkładu respektuje preferowany rozmiar komponentu w różny sposób
GridBagLayout jest najbardziej skomplikowanym rozkładem ale jednocześnie najbardziej funkcjoanlnym/elastycznym
GridBagConstraints wykorzstywany w przypadku konieczności wyspecifikowania rozkładu dla każdego komponentu
Złożone rozkłady mogą być uproszczone przez zastosowanie zagnieżdżonych kontenerów
W AWT jako element odzielający wykorzystuje się Canavas a w Swing Box
Zdarzenia (Events)
Cel: potrzeba dowiedzenia się o czymś, co wydarzyło się poza obiektem.
Zdarzenie (Event) – nośnik informacji o zajściu określonej sytuacji
Przykład 1: użytkownik wciska przycisk na ekranie
Przykład 2: Przyjście pewnej porcji informacji na port serwera (aplikacja web chat)
Obiekt, w którym pojawiło się zdarzenie – generator zdarzeń (event generator). Np. przycisk na ekranie.
Obiekt, który wykona pewne zadanie po otrzymaniu zdarzenia –
event handler. Dla wybranego zdarzenia może być wiele event
handlers, które mogą wykonać różne zadania.
Mechanizm obsługi zdarzeń
Archaiczne podejście do obsługi zdarzeń: polling.
Przebieganie stanu obiektów w pętli. Podejście absorbujące dużą ilość zasobów (olbrzymia pętla).
Generator zdarzeń udostępnia usługę rejestracji –
pamięta, do których event handlers powinien przekazać zdarzenia
Rejestracja event handlers u generatora zdarzeń
Wykorzystanie diagramów MSC do modelowania systemów sterowanych zdarzeniami.
Message Driven Application - Zastosowania w
systemach rozproszonych.
Mechanizm obsługi zdarzeń w Javie
Generatory zdarzeń
udostępnia JVM. Programista implementuje wyłączenie
zachowanie event handlers – tzw. nasłuchiwaczy (listeners) .
W razie wyszukanych potrzeb programista może jednak
zaimplementować własne generatory zdarzeń.
Po implementacji event
handlers należy zarejestrować
Przykład: Java Button
Generuje zdarzenia ActionEvents
Nasłuchiwacz rejestruje się u Java Button po przez wywołanie metody
addActionListner z parametrem
wskazującym kto będzie nasłuchiwał.
Metoda ta generuje wiadomość addActionListener
Java Button pamięta, kto się u niego zarejestrował (automatyczny mechanizm dostarczany przez JVM)
W momencie wystąpienia zdarzenia w Java Button, Java Button generuje wiadomość actionPerformed, do każdego z
zarjestrowanych nasłuchiwaczy.
Listner powinien mieć zaimplementowaną metodę actionPerformed, która zostanie
Mechanizm obsługi zdarzeń diagram MSC
Button Button = new Button(„Klik!");
Button.addActionListener(new Nasluchiwacz());
// rejestracja
class Nasluchiwacz implements ActionListener { public void actionPerformed(ActionEvent e) { System.out.println(„nasinieto przycisk");
// wykonanie zadania }
}
Przykład 2 – hierarchia generowania zdarzeń przez komponenty.
public boolean handleEvent(Event e)
e – parametr z referencją na zdarzenie, które powstało
Ważna jest wartość zawracana przez handleEvent. Informuje JVM, czy zdarzenie zostało w pełni obsłużone
Zdarzenie propaguje w górę
drzewa, do momentu, kiedy nie
zostanie poprawnie obsłużone
Metody pomocnicze do obsługi zdarzeń
W przypadku konieczności obsłużenia wybranych zdarzeń można skorzystać z funkcji pomocniczych
Metoda pomocnicza zwraca wartość false w przypadku, gdy zdarzenie nie zostanie w pełni obsłużone
Przykład 3
action(Event evt, Object what)
gotFocus(Event evt, Object what)
lostFocus(Event evt, Object what)
mouseEnter(Event evt, int x, int y)
mouseExit(Event evt, int x, int y)
mouseMove(Event evt, int x, int y)
mouseUp(Event evt, int x, int y)
mouseDown(Event evt, int x, int y)
mouseDrag(Event evt, int x, int y)
keyDown(Event evt, int key)
keyUp(Event evt, int key)
Przykładowy zestaw zdarzeń
Window Events
WINDOW_DESTROY (201)
WINDOW_EXPOSE (202)
WINDOW_ICONIFY (203)
WINDOW_DEICONIFY (204)
WINDOW_MOVED (205)
Keyboard Events
KEY_PRESS (401)
KEY_RELEASE (402)
KEY_ACTION (403)
KEY_ACTION_RELEASE
Mous Events
MOUSE_DOWN 501
MOUSE_UP 502
MOUSE_MOVE 503
MOUSE_ENTER 504
MOUSE_EXIT 505
MOUSE_DRAG
Różne zdarzenia
ACTION_EVENT 1001
Przykłady zdarzeń
Klasa Event
long when Chwila, w które zdarzenie wystąpiło.
int id Typ zdarzenia (patrz następny slajd)
int x Współrzędna X określająca miejsce, w którym zdarzenie się pojawiło w odniesieniu do komponentu, który jest aktualnie przetwarzany. Początkowa
wartość x jest to górny lewy róg.
int y Współrzędna X określająca miejsce, w którym zdarzenie się pojawiło w odniesieniu do komponentu, który jest aktualnie przetwarzany. Początkowa
wartość x jest to górny lewy róg.
int key Dla zdarzeń pochodzących z klawiatury. Jest to kod wciśniętego klawisza. Przeważnie jest to wartość zapisana w postaci unicode.
int modifiers arytmetyczna reprezentacja wartości SHIFT_MASK, CTRL_MASK, META_MASK, and ALT_MASK. Wartość zostaje zmieniona odpowiednio dla zmiany stanu klawiszy shift, control, meta, alt.
int clickCount Liczba kliknięć myszy. Pole te jest istotne wyłącznie przy zdarzeniu MOUSE_DOWN.
Object arg Zależny od zdarzenia argument. Dla obiektów Button, object jest ciągiem znaków, który zawiera jego etykietę.
Przykład 1. Aplikacja obsługująca
zdarzenia
Java 2D
Java 2D API umożliwia pracę z obrazami, tekstem i grafiką jako rozszerzenie AWT
Zakres dostarczanej funkcjonalności:
Ujednolicony model renderingu dla różnych rodzajów wyświetlaczy i drukarek (user space)
Duży zbiór różnych podstawowych kształtów geometrycznych takich jak:
prostokąty, krzywe, elipsy jak i również mechanizm do renderowania dowolnych kształtów.
Mechanizm dla wykrywania kilknięć na kształtach, tekście i obrazkach
Sterowanie sposobem rednerowania zachodzących na siebie obiektów
Zarządzanie kolorami
Wsparcie dla wydruków złożonych dokumentów
Sterowanie jakością renderowanych obiektów (anty-aliasing)
Układ współrzędnych
Java 2D rozróżnia dwa układy współrzędnych
Przestrzeń użytkownika (user space) – miejsce, w którym obiekty są
specyfikowane
Przestrzeń urządzeń (device space) – układ
współrzędnych związanych z urządzeniem, na którym ma zostać wyświetlona wyspecyfikowana grafika
(0,0) x
y
Typem dla x i y jest integer. Wspierany jest również float i double.
Java 2D rendering
Java udostępnia wspólny
mechanizm modelowania grafiki dla różnych urządzeń
W przypadku konieczności
wyświetlenia/wykreślenia danego kształtu wywoływane są
automatycznie metody paint() lub update() z kontekstem
graficznym Graphics. Metody te zawiera każdy obiekt
rozszerzający Component.
Pakiet java.awt.Graphics2D oferuje następujące możliwości:
rysowanie podstawowych kształtów geometrycznych z
uwzględnieniem krawędzi (metody draw)
wypełnianie kształtów kolorem lub określonym wzorem (metody fill)
rysowanie tekstu (drawString).
Określenie czcionki wskazuje w jaki sposób ma być danych tekst przekształcony w obiekt graficzny, który jest wypełniony kolorem lub wzorem
rysowanie obrazków (metoda drawImage)
Metody wykorzystywane przy rysowaniu w Java 2D
Metody do rysowania można podzielić na dwie grupy
Metody definiujące kształt (metody draw, fill)
Metody określające w jaki sposób ten kształt ma być narysowany – zmiana atrybutów kontekstu (Graphics)
W celu użycia dodatkowych funkcjonalności oferowanych przez Java 2D należy rzutować obiekt typu Graphics na
Graphics2D
Możliwość modyfikacji atrybutów związanych z określonym
kontekstem
modyfikacja szerokości linii/krawędzi rysunku
zmiana sposobu łączenia linii/krawędzi
przekształcanie rysunku:
obracanie skalowanie lub przycinanie
określanie koloru i wzoru wypełnienia kształtu
określenie w jaki sposób obiekty są ze sobą skomponowane
Java 2D vs AWT
public void paint(Graphics g) { // ustawianie atrybutów pędzela g.setColor(someColor);
g.setFont(someLimitedFont);
// kreślenie kształtów g.drawString(…);
g.drawLine(…)
g.drawRect(…); // outline g.fillRect(…); // solid
g.drawPolygon(…); // outline g.fillPolygon(…); // solid g.drawOval(…); // outline g.fillOval(…); // solid //etc…
}
public void paintComponent(Graphics g) { // czyszczenie obrazu
super.paintComponent(g);
// rzutowanie kontekstu na konteskt Java2D Graphics2D g2d = (Graphics2D)g;
// Set pen parameters
g2d.setPaint(fillColorOrPattern);
g2d.setStroke(penThicknessOrPattern);
g2d.setComposite(someAlphaComposite);
g2d.setFont(anyFont);
g2d.translate(…);
g2d.rotate(…);
g2d.scale(…);
g2d.shear(…);
g2d.setTransform(someAffineTransform);
// definiowanie własnego kształtu SomeShape s = new SomeShape(…);
// rysowanie kształtu g2d.draw(s); // outline g2d.fill(s); // solid }
Figury podstawowe - rysowanie (1)
Java 2D API udostępnia podstawowe kształty: linia, punkt, prostokąt, etc…
w pakiecie java.awt.geom
Klasy reprezentujące kształty implementują interfejs
Shape: pozwala opisać krzywą
PathIterator: określa w jaki sposób są pobierane elementy krzywej.
Należy uzyskać obiekt typu Graphics2D
Każda funkcja wymaga zdefiniowana punktu zaczepienia
np. java.awt.Graphics.drawLine(int x1, int y1, int x2, int y2).
(x1, y1) początek linii, a (x2, y2) koniec linii.
Jeśli chcemy narysować kształt z Java 2D możemy użyć funkcji draw
g2.draw(new Line2D.Double(x1, y1, x2, y2));
lub Line2D.Float(float X1, float Y1, float X2, float Y2) ;
Figury podstawowe - rysowanie (2)
Krzywe kwadratowe:
QuadCurve2D
Metoda setCurve – pozwala na określenie dwóch punktów
końcowych oraz punktu sterującego krzywą
Krzywe sześcienne:
CubicCurve2D
Kawałek parametryzowanej krzywej sześciennej
Metoda setCurve analogiczna do metody setCurve z krzywej kwadratowej poszerzona o drugi punkt kontrlony
QuadCurve2D q =
new QuadCurve2D.Float();
q.setCurve(0, 0, 200, 600, 400, 0);
g2d.draw(q);
CubicCurve2D q =
new CubicCurve2D.Float();
q.setCurve(0, 0, 50, 50, 10,100, 400, 0);
g2d.draw(q);
Figury podstawowe - rysowanie (3)
Klasa Rectangle dziedziczy po RectangularShape i
implementuje interfejs Shape oraz kilka dodatkowych metod pozwalających na określenie położenia, rozmiaru, środka, etc…
Klasa RoundRectangle definiuje prostokąt z zaokrąglonymi
wierzchołkami.
Do wyspecyfikowania prostokąta wymagane są: położenie, wysokość, szerokość, wartość wysokości kąta zaokrąglenia, wartość szeorkości kąta zaokrąglenia
Figury podstawowe - rysowanie (4)
Elipsa – krzywa zdefiniowana w typie Ellipse2d
Do narysowania wymagana jest położenie oraz wysokość i szerokość
Łuk – część elipsy. Zdefiniowana w klasie Arc2D. Do opisania potrzebne jest: położenie, wysokość i szerokość prostokąta w który jest wpisana elipsa, początek i koniec kąta, typ zamknięcia.
Typy zamknięcia: OPEN, PIE, CHORD
g2.draw(new Ellipse2D.Double(x, y,
rectwidth, rectheight));
g2.draw(new Arc2D.Double(x, y,
rectwidth,
rectheight, 90, 135,
Arc2D.OPEN));
Własne kształty
Do rysowania własnych kształtów została stworzona klasa
GeneralPath.
GeneralPath implementuje
interfejs Shape i pozwala rysować krzywe, które złożone są z
podstawowych kształtów: linie, krzywe sześcienne i kwadratowe,
Metody do kształtowania GeneralPath
moveTo(float x, float y) – przesuń aktualny punkt ścieżki do danego punktu
lineTo(float x, float y) – dodaj kawałek linii do obecnej ścieżki
quadTo(float ctrlx, float ctrly, float x2, floaty2) – dodaj krzywą
sześcienną do aktualnej ścieżki.
curveTo(float ctrlx1, float ctrly1, float ctrlx2, float ctrly2, float x3, floaty3) – dodaj krzywą sześcieną do aktualnej ścieżki
int x2Points[] = {0, 90, 0, 90};
int y2Points[] = {0, 40, 40, 0};
GeneralPath lamana =
new GeneralPath(GeneralPath.WIND_EVEN_ODD, x2Points.length);
lamana.moveTo (x2Points[0], y2Points[0]);
Określenie grubości i rodzaju krawędzi (stroking) oraz wypełnienia
Wygląd kształtów możemy modyfikować po przez:
wypełnienie (filling) – wypełnianie kształtu określonym kolorem, gradientem lub wzorem
określanie krawędzi (stroking) – krawędź może mieć
grubość, kolor, styl
Ażeby narysować kształty należy zmienić przed
wywołaniem metody draw ustawienia kontsktu
Graphics2D.
Zaokrąglony prostokąt z przerywaną linią final static float przer1[] = {10.0f};
final static BasicStroke przer = new
BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
10.0f, przer1, 0.0f);
g2.setStroke(przer);
g2.draw(new RoundRectangle2D.Double(x, y, rectWidth, rectHeight, 10, 10));
Gradient na elpisie
czerwon2bialy = new GradientPaint(0,0, color.RED,100, 0,color.WHITE);
g2.setPaint(czerwony2bialy);
g2.fill (new
Ellipse2D.Double(0, 0, 100, 50));
Style linii
Style linii są definiowane przez atrybut krawędzi dla danego kontekstu Graphics
W celu ustawienia wybranego stylu linii należy utworzyć
instancje BasicStroke i ustawić dla kontekstu Graphics za
pomocą funkcji setStroke.
Metoda draw narysuje kształt zgodnie z ustawioną definicją linii
Właściwości stylu linii:
Grubość linii
Rodzaj połączenia linii:
JOIN_BEVEL, JOIN_MITER, JOIN_ROUND
Styl zakończenia linii:
CAP_BUTT, CAP_ROUND, CAP_SQUARE
Przerywanie linii. Ażeby
zdefiniować przerywanie linii
należy określić długość części
widocznej i niewidocznej i
Wzory wypełnienia
Wzory wypełnienia są definiowane jako atrybut procesu malowania
Wybranie wzoru wypełnienia wymaga utworzenia obiektu
implementującego interfejs Paint oraz ustawienia go dla wybranego kontekstu graficznego Graphics za pomocą metody setPaint
Trzy klasy implementują interfejs Paint:
Color,
GradientPaint – określony przez punkt, w którym rozpoczyna się dany kolor oraz punkt, w którym kończy się dany kolor.
TexturePaint – definiowany przez BufferImage. Należy wskazać obraz
oraz rozmiar prostokąta z obrazem, który będzie powielany
Praca z obrazami
Obrazy są obiektami, które posiadają wysokość i szerokość oraz własny układ współrzędnych
Możliwe akcje do wykonania na obrazach:
Ładowanie zewnętrznych obrazów w formatach GIF, PNG, JPEG do wewnętrznej reprezentacji obrazu w Java 2D
Bezpośrednie tworzenie obrazu i jego renderowanie
Bezpośrednie rysowanie zawartości obrazu na
powierzchni przeznaczonej do rysowania
Klasy związane z obrazami
java.awt.Image – jest to klasa bazowa dla pozostałych klas związanych z obrazami
przechowująca informację o obrazie jako tablica pikseli
java.awt.image.BufferdImage – klasa dziedzicząca po Image umożliwiająca bezpośrednią pracę nad obrazem (np.
ustawianie kolorów pikseli). Aplikacje mogą
bezpośrednio tworzyć instancję tej klasy
Klasa BufferedImage
Przeprowadzane operacje na obrazie realizowane są
bezpośrednio w pamięci
Udostępnia metody do
przechowywania, interpretacji i uzyskiwania danych
dotyczących pikseli
Może być renderowany przez Graphics lub Graphcis2D
BufferedImage określony jest przez:
Raster
Funkcje Raster’a:
Reprezentuje układ
współrzędnych związanych z obrazem
Zarządza danymi dot. obrazu bezpośrednio w pamięci
Udostępnia mechanizm tworzenia różnych
podobrazów z pojedynczego bufora z danymi o obrazie
Oferuje metody pozwalające
na dostęp do poszczególnych
pikseli obrazu
Czytanie/ładowanie obrazu
Java 2D umożliwia ładowanie obrazu z zewnętrznego formatu za pomocą
Image I/O API.
Image I/O API obsługuje następujące formaty: GIF, PNG, JPEG, BMP, WBMP
Rozpoznanie typu kodowania obrazu realizowane jest automatycznie
Wczytywanie obrazu może być
realizowane również nie tylko z pliku, ale także ze strumienia danych
Więcej informacji na temat Image I/O API:
http://java.sun.com/j2se/1.4.2/docs/g
uide/imageio/spec/imageio_guideTOC.fm .html
Przykład wczytania obrazu
BufferedImage img = null;
try {
img = ImageIO.read(new File("strawberry.jpg"));
} catch (IOException e) {}
Rysowanie obrazów
Do rysowania obrazów w danym położeniu służy funkcja:
boolean Graphics.drawImage(Image img, int x, int y, ImageObserver observer);
x, y – określają pozycję obrazu
observer informuje aplikację o fakcie załadowania obrazu w przypadku asynchronicznym. Nie jest wymagany dla BufferedImage
Obraz jest rysowany 1:1 w przestrzeni użytkownika (user space)
Przykład metody umożliwiającej rysowanie części obrazu, skalowanie oraz stosowanie filtrów:
boolean Graphics.drawImage(Image img, int dstx1, int dsty1, int dstx2, int dsty2, int srcx1, int srcy1, int srcx2, int srcy2, ImageObserver observer);
src – reprezentuje obszar, który będzie skopiowany i odrysowany
dst – określają obszar, w którym będą przerysowane dane z src
Rozmiary obrazka obliczane są analogicznie dla wysokości i szerokości w następujący sposób: srcx2-scrx1
Stosowanie filtrów
Filtrowanie danego obrazka polega na utworzeniu nowego z użyciem pewnego algorytmu modyfikującego poszczególne piksele (np. modyfikacja
kanału alpha, czyli przeźroczystości)
void
Graphics2D.drawImage(
BufferedImage img, BufferedImageOp op, int x, int y)
BufferedImageOp – klasa implementująca określony filtr
Przykładowe filtry:
ConvolveOp. Każdy z wyjściowych pikseli jest obliczany z pośród go otaczających. Może być wykorzystany do rozmywania lub wyostrzania
obrazów.
AffineTransformp. Filtr ten mapuje piksele ze źródłowej pozycji do innego położenia docelowego dokonującą transformacji na lokalizacji pikseli
LookupOp. Filtr dokonuje zamiany kolorów na podstawie dostarczonej tablicy kolorów.
RescaleOp. Filtr mnoży wartości opisujące kolor przez ten sam
współczynnik. Może być wykorzystany do rozjaśniania lub przyciemnia obrazu lub zmiany przeźroczystości.
Tworzenie i rysowanie obrazów
Dowolny obraz może być utworzony z wykorzystaniem następujący konstruktorów:
new BufferedImage(width, height, type) – konstruuje BufferedImage dla wybranego predefiniowanego typu obrazu of
new BufferedImage(width, height, type, colorModel) – konstruuje BufferedImage dla wybranego typu obrazu: TYPE_BYTE_BINARY lub TYPE_BYTE_INDEXED.
new BufferedImage(colorModel, raster, premultiplied, properties) – konstruuje nowy BufferedImage z określonym Modelem Kolorów i Rastrem.
Obraz może być stworzony nie tylko na ekranie. Obraz może być
rozważany w kontekście powierzchni po której można rysować. Do tego celu służy metoda createGraphics()
BufferedImage off_Image = new BufferedImage(100, 50, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = off_Image.createGraphics();
Podwójne buforowanie
Obraz tworzony w pamięci może być wykorzystany do budowy mechanizmu podwójnego buforowania.
Mechanizm podwójnego buforowania zmniejsza użycie zasobów dzięki czemu animacja jest płynna
W tym przypadku przetworzenie obrazu realizowane w pamięci po czym obraz jest kopiowany na ekran
Java 2D umożliwiających dostęp do mechanizmów przyśpieszających obróbkę obrazów w buforze:
Metoda getCapabilities pozwala określić, czy wyświetlanie obrazu jest przyśpieszone (accelerated).
Metoda setAccelerationPriority pozwala na ustawienie współczynnika określającego jak ważne jest przyśpieszenie wyświetlania danego obrazu
Metoda getAccelerationPriority zwraca informacje na temat priorytetu przyśpieszenia wyświetlania obrazu.
Zapisywanie obrazu
Zapisanie obrazu na dysku z BufferedImage z użyciem Image I/O API
static boolean ImageIO.write(RenderedImage im, String formatName, File output) throws IOException
Metoda ImageO.write woła plug-in dla danego typu obrazka, które nazwa przekazywana jest w parametrze formatName. Dzięki temu można łatwo rozszerzyć listę obsługiwanych formatów.
Standardowo obsługiwane formaty: JPEG, PNG, GIF, BMP i WBMP
Metoda String writerNames[] = ImageIO.getWriterFormatNames(); zwraca listę wspieranych formatów przez JRE
try {
BufferedImage bi = getMyImage();
// zapisanie obrazu
Właściwości obrazów
Format Zalety Wady
GIF
Wspiera animację i przeźroczystość Tylko 256 kolorówPNG
Bardzo dobra alternatywa dlakolorowych obrazów, które nie mogą być zakodowane stratnie w
porównaniu do JPG i GIF
Nie wspiera animacji
JPG
Bardzo dobry dla obrazów będącychzdjęciami. Kompresja stratna, źle się
zachowuje w przypadku kodowania tekstu, i innych rodzajów obrazu, które muszą zachować ostrość.