8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 1
8. Multimedia. Klasa
Graphics
8.1 Operowanie na obrazach
8.2 Animacje
8.3 D
ź
wi
ę
ki
8.4
Graphics
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 2
8.1 Operowanie na obrazach
Operacje na obrazach wspomagaj
ą
pakiety:
java.applet, java.awt, java.awt.image.
Obraz reprezentowany jest jako obiekt klasy
java.awt.Image
.
Podstawowa metoda dla obrazu w klasie
java.awt.Graphics
to
drawImage
, w klasie
java.awt.Toolkit
- metoda
getImage
a tak
ż
e
metody klasy
java.awt.MediaTracker
.
W pakiecie
java.applet
metoda klasy
Applet -
getImage
– umo
ż
liwia
pobieranie obrazów z plików graficznych.
Pakiet
java.awt.image
zapewnia interfejsy i klasy dla tworzenia, (np..
MemoryImageSource
),
przetwarzania
(np.
ConvolveOp,
RGBImageFilter
) i nadzorowania ładowania (np.
ImageObserver
).
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 3
1) Ładowanie obrazów
Metody
getImage()
Obrazy w formatach
GIF
,
JPEG
lub
PNG
ładowane mog
ą
by
ć
metodami
getImage
()
deklarowanymi w klasach
Applet
i
Toolkit
. Np.
myImage = getImage(URL);
// w klasach pochodnych od Applet
// LUB w klasach pochodnych od Toolkit:
myImage = Toolkit.getDefaultToolkit().getImage(nazwaPlikuLubURL);
Metody
getImage()
powracaj
ą
natychmiast
, nie oczekuj
ą
c na
potwierdzenie istnienia obrazu ani na jego załadowanie. Ładowanie
odb
ę
dzie si
ę
wtedy, gdy obraz po raz pierwszy b
ę
dzie malowany w
programie.
W klasie
Toolkit
istniej
ą
dwie deklaracje metod o tej nazwie:
public abstract
Image getImage(URL url);
public abstract
Image getImage(String filename);
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 4
Metody te mog
ą
by
ć
wołane w aplikacjach lub apletach (ale w tym
drugim przypadku aplety musz
ą
spełnia
ć
warunki dost
ę
pu).
Np.
Toolkit toolkit = Toolkit.getDefaultToolkit();
Image image1 = toolkit.getImage("nazwaObrazu.gif");
Image image2 = toolkit.getImage(new URL("http://www.pw.edu.pl/pw.gif"));
W klasie
Applet
istniej
ą
dwie wersje tej metody:
public
Image getImage(URL url);
public
Image getImage(URL url, String name);
Mog
ą
by
ć
wołane tylko w apletach i dopiero po uzyskaniu pełnego
kontekstu przez aplet – nie w konstruktorze ani w instrukcji deklaracji
obiektu.
Np.
// W metodzie pewnej klasy pochodnej od Applet:
Image image1 = getImage(getCodeBase(), "pw.gif");
Image image2 = getImage(getDocumentBase(), "pw.jpeg");
Image image3 = getImage( new URL("http://www.pw.edu.pl/pw.gif"));
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 5
2) Tworzenie obrazów za pomoc
ą
klasy
MemoryImageSource
Nowe obrazy mog
ą
by
ć
tworzone od pocz
ą
tku dzi
ę
ki klasie
java.awt.image.
MemoryImageSource
.
Przykład 8.1.
Fragment programu przeznaczony dla utworzenia obrazu
o rozmiarze 100 x 100, przedstawiaj
ą
cego odcienie od czarnego do
niebieskiego (wzdłu
ż
osi X) i odcienie od czarnego do czerwonego
(wzdłu
ż
osi Y):
int w = 100;
int h = 100;
int[] pix = new int[w * h];
int index = 0;
for (int y = 0; y < h; y++) {
int red = (y * 255) / (h - 1);
for (int x = 0; x < w; x++) {
int blue = (x * 255) / (w - 1);
pix[index++] = (255 << 24) | (red << 16) | blue;
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 6
}
}
Image img = createImage(new MemoryImageSource(w, h, pix, 0, w));
3) Nadzorowanie ładowania obrazów
Proces ładowania obrazu mo
ż
e by
ć
nadzorowany przez klas
ę
java.awt.
MediaTracker
lub przez implementacj
ę
metody
imageUpdate()
(zdefiniowanej w interfejsie
java.awt.image.
ImageObserver
).
Interfejs
ImageObserver
Wymaga implementacji metody
imageUpdate()
i rejestracji obiektu jako
„obserwatora” – zwykle ma to miejsce poprzez przekazanie obiektu
typu implementuj
ą
cego
ImageObserver
do metody
drawImage
().
public boolean imageUpdate(Image img,
int infoflags, int x, int y, int width, int height);
Metoda powinna zwróci
ć
false wtedy, gdy przakzane argumenty
wskazuj
ą
,
ż
e cały obraz został juz załadowany.
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 7
4) Rysowanie obrazu
Metoda
drawImage()
wołana dla obiektu klasy
Graphics
przekazanego
do metody
paintComponent().
Np.:
// Normalny rozmiar obrazu. Lokalizacja pocz
ą
tku w górnym lewym
// rogu obszaru komponentu.
g.drawImage(myImage, 0, 0, this);
// Obraz przeskalowany do rozmiaru: 300 x 62 piksele i lokalizacji
// pocz
ą
tku w punkcie (90, 0) obszaru komponentu:
g.drawImage(myImage, 90, 0, 300, 62, this);
Metoda
drawImage
tak
ż
e (jak
getImage()
) działa asynchronicznie
wzgl
ę
dem ładowania obrazu - powraca po narysowaniu fragmentu
obrazu, który został dot
ą
d załadowany.
Cztery metody
drawImage
w klasie
Graphics
(zwracaj
ą
wynik typu
“
boolean
”):
boolean drawImage (Image img, int x, int y, ImageObserver observer)
boolean drawImage (Image img, int x, int y, int width, int height,
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 8
ImageObserver observer)
boolean drawImage (Image img, int x, int y, Color bgcolor,
ImageObserver observer)
boolean drawImage (Image img, int x, int y, int width, int height,
Color bgcolor, ImageObserver observer)
Znaczenie parametrów metod
drawImage()
:
Image img – rysowany obraz;
int x, int y – współrzędne górnego lewego rogu obrazu ;
int width, int height – szerokość i wysokość obrazu (w pikselach);
Color bgcolor – kolor tła.
ImageObserver observer – rejestracja obiektu implementującego
interfejs ImageObserver – ten obiekt będzie powiadamiany o ładowaniu
obrazu.
Klasa
Component
implementuje interfejs
ImageObserver
, czyli ka
ż
dy
komponent GUI mo
ż
e przekaza
ć
siebie (poprzez
this
) jako
obserwatora. Ta implementacja metody
imageUpdate
interfejsu
wywołuje metod
ę
repaint
, gdy obraz jest ładowany.
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 9
8.2 Wykonanie animacji
1) P
ę
tla animacji z wykorzystaniem klasy
Timer
P
ę
tla animacji powinna wykonywa
ć
si
ę
w osobnym w
ą
tku, a nie w
metodzie
paintComponent()
, gdy
ż
to umie
ś
ciłoby animacj
ę
w w
ą
tku
obsługi zdarze
ń
(“event-dispatching”).
Przykład 8.2
. Prosta animacja podaj
ą
ca kolejny numer ramki z
cz
ę
sto
ś
ci
ą
10 ramek na sekund
ę
:
public class AnimatorClass ... implements ActionListener {
int frameNumber = -1;
Timer timer;
boolean frozen = false;
// Nie blokujemy animacji
JLabel label;
// Komponent realizujący rysowanie
// W kodzie inicjalizacji GUI:
// Na podstawie liczby ramek na sekundę fps określamy odstęp czasu - delay
delay = (fps > 0) ? (1000 / fps) : 100;
...
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 10
// Obiekt klasy Timer będzie wołał obsługę akcji w naszym obiekcie.
timer = new Timer(delay, this);
// Obiekt klasy Timer generować będzie
// zdarzenie akcji co pewną liczbę „delay” milisekund
// i dalsze ustawienie komponentów w GUI.
...
// Gdy pojawi się GUI aplikacji:
startAnimation();
// Gdy GUI jest ukrywane:
stopAnimation();
…
//Obsługa zdarzenia akcji dla timer-a:
public void actionPerformed(ActionEvent e) {
frameNumber++;
// Zwiększ numer ramki
label.setText("Frame " + frameNumber);
// Zmiana tekstu i narysowanie
}
// Metody uruchamiania i zatrzymywania animacji:
public synchronized void startAnimation() {
if (frozen) {
// Nie wykonuj animacji
.
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 11
} else {
// Rozpocznij animację !
...
timer.start();
}
public synchronized void stopAnimation() {
...
timer.stop();
}
Uruchamianie i zatrzymanie animacji mo
ż
e by
ć
te
ż
inicjowane w
obsłudze zdarze
ń
myszy dla komponentu realizuj
ą
cego animacj
ę
:
public void mousePressed(MouseEvent e) {
if (frozen) { frozen = false;
startAnimation();
} else { frozen = true;
stopAnimation();
}
}
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 12
2) Przesuwanie obrazu po ekranie
Przykład 8.3.
Program realizuje animacj
ę
, podczas której obraz rakiety
przesuwa si
ę
na tle obrazu gwiazd:
rocketship.gif:
starfield.gif:
Jedna klatka animacji:
Obraz rakiety posiada przezroczyste tło.
W panelu definiowanym przez programist
ę
malowane s
ą
dwa obrazy, z
których pozycja jednego nie zale
ż
y a drugiego zale
ż
y od numeru
aktualnej ramki.
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 13
...// Miejsce inicjalizacji obrazów:
Image background = getImage(getCodeBase(), "images/rocketship.gif");
Image foreground = getImage(getCodeBase(), "images/starfield.gif");
...
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Rysuje obszar komponentu
int compWidth = getWidth();
int compHeight = getHeight();
// Namaluj obraz w tle, je
ś
li posiada wła
ś
ciwy rozmiar:
imageWidth = background.getWidth(this);
imageHeight = background.getHeight(this);
if ((imageWidth > 0) && (imageHeight > 0)) {
g.drawImage(background, (compWidth - imageWidth)/2,
(compHeight - imageHeight)/2, this);
}
// Namaluj obraz na 1-szym planie, je
ś
li posiada wła
ś
ciwy rozmiar:
imageWidth = foreground.getWidth(this);
imageHeight = foreground.getHeight(this);
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 14
if ((imageWidth > 0) && (imageHeight > 0)) {
g.drawImage(foreground,
((frameNumber*5) % (imageWidth + compWidth)) - imageWidth,
(compHeight - imageHeight)/2, this);
}
}
Program wymaga jeszcze synchronizacji rysowania z załadowaniem
obu obrazów – odczekania na pełne załadowanie obu obrazów – i
przeskalowania obrazu tła tak, aby wypełniał cały obszar panelu.
Do tego celu posłu
ż
y klasa
MediaTracker
, omówiona w punkcie 4.
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 15
3) Wy
ś
wietlanie sekwencji obrazów
Przykład 8.4.
Aplet wy
ś
wietla sekwencj
ę
10 obrazów:
T1.gif:
T2.gif:
T3.gif:
T4.gif:
T5.gif:
T6.gif:
T7.gif:
T8.gif:
T9.gif:
T10.gif:
. . .// W kodzie inicjalizacji:
Image[] images = new Image[10];
for (int i = 1; i <= 10; i++) {
images[i-1] = getImage(getCodeBase(), "images/duke/T"+i+".gif");
}
. . .// W metodzie
paintComponent
- w zale
ż
no
ś
ci od numeru ramki:
g.drawImage(images[frameNumber % 10], 0, 0, this);
Alternatywna metoda animacji to wykorzystanie komponentu etykiety
JLabel
i ustawianie wy
ś
wietlanego obrazu metod
ą
setIcon
.
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 16
4) Animacja z wykorzystaniem
MediaTracker
Klasa
MediaTracker
umo
ż
liwi efektywne ładowanie obrazów i opó
ź
ni
ich wy
ś
wietlenie do momentu, gdy b
ę
d
ą
one dost
ę
pne w cało
ś
ci.
Klasa
MediaTracker
posiada metody dla wcze
ś
niejszego ni
ż
potrzebne
(tzn. podczas rysowania komponentu) załadowania obrazów.
Poni
ż
sze metody sprawdzaj
ą
, czy pozostały jeszcze fragmenty obrazu
(lub obrazy) wymagaj
ą
ce załadowania.
public boolean checkAll()
checkAll(false, true)
// sprawdza, czy
wszystkie obrazy nadzorowane przez ten obiekt zostały załadowane (lub
wystąpił błąd ładowania)
public boolean checkAll(boolean load)
checkAll(load, true)
//
sprawdza, czy wszystkie obrazy nadzorowane przez ten obiekt zostały
załadowane (lub wystąpił błąd ładowania); jeśli load = true to inicjuje
ładowanie wszystkich przewidzianych ale jeszcze nieładowanych
obrazów.
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 17
public boolean checkID(int id)
// sprawdza, czy obrazy o podanym
identyfikatorze, nadzorowane przez ten obiekt, zostały załadowane (lub
wystąpił błąd ładowania)
public boolean checkID(int id, boolean load)
// sprawdza, czy obrazy o
podanym obrazy o podanym identyfikatorze, nadzorowane przez ten
obiekt, zostały załadowane (lub wystąpił błąd ładowania); jeśli load = true
to inicjuje ładowanie wszystkich jeszcze nieładowanych obrazów.
Poni
ż
sze metody inicjuj
ą
ładowanie i oczekuj
ą
na załadowanie całych
obrazów:
public void waitForID (int id)
// inicjuje ładowanie obrazów o podanym
identyfikatorze i czeka na zakończenie ładowania
public void waitForID (int id, long ms)
// inicjuje ładowanie obrazów o
podanym identyfikatorze i czeka na zakończenie ładowania, ale nie dłużej
niż liczbę ms milisekund
public void waitForAll()
// inicjuje ładowanie obrazów nadzorowanych
przez ten obiekt i czeka na zakończenie ładowania
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 18
public void waitForAll(long ms)
// inicjuje ładowanie obrazów
nadzorowanych przez ten obiekt i czeka na zakończenie ładowania, ale nie
dłużej niż liczbę ms milisekund
Sprawdzenie stanu ładowania obrazów.
public int statusID(int id, boolean load)
// sprawdza stan ładowania
obrazów o podanym identyfikatorze id, nadzorowanych przez dany obiekt,
w postaci bitowej jao wynik operacji OR na stanie wszystkich tych
obrazów – możliwe stany to: 0 – ładowanie jeszcze nie rozpoczęte,
LOADING, ABORTED, ERRORED, COMPLETE;
jeśli load = true to
inicjuje ładowanie wszystkich jeszcze nieładowanych obrazów.
public int statusAll(boolean load)
// sprawdza stan ładowania wszystkich
obrazów, nadzorowanych przez dany obiekt.
Metody klasy
MediaTracker
dla dodawania nadzorowanych obrazów:
public void addImage(Image image, int id)
// dodaj obraz z podanym
identyfikatorem
public synchronized void addImage(Image image, int id, int w, int h)
//
dodaj obraz z podanym identyfikatorem; obraz ma być skalowany na
podany rozmiar
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 19
Przykład 8.5
. Modyfikacja poprzedniego apletu (z przykładu 8.4)
korzysta z metod
MediaTracker
- waitForAll
i
checkAll
. Do momentu
pełnego załadowania wszystkich obrazów wy
ś
wietla komunikat:
"Please wait..."
Fragmenty kodu z wyró
ż
nionymi zmianami w porównaniu z
poprzednim przykładem:
...// W miejscu deklaracji obiektów :
MediaTracker tracker;
tracker = new MediaTracker(this);
...// W metodzie init:
for (int i = 1; i <= 10; i++) {
images[i-1] = getImage(getCodeBase(), "images/duke/T"+i+".gif");
}
...// W metodzie buildUI, wołanej przez init (dla apletu) wzgl. main
// (dla aplikacji)
for (int i = 1; i <= 10; i++) {
tracker.addImage(images[i-1], 0);
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 20
}
...// Na pocz
ą
tku obsługi w metodzie actionPerformed :
try {
// Rozpocznij ładowanie obrazów. Czekaj na ich załadowanie.
tracker.waitForAll();
} catch (InterruptedException e) {}
...// W metodzie paintComponent:
// Jeśli nie załadowano wszystkich obrazów to wyczyść tło i wyświetl
// napis ze stanem ładowania:
if (!tracker.checkAll()) {
g.clearRect(0, 0, d.width, d.height);
g.drawString("Please wait...", 0, d.height/2);
}
// ale jeśli wszystkie obrazy zostały załadowane – namaluj je:
else {
...// ten sam kod co uprzednio ...
}
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 21
5) Efektywno
ść
ładowania obrazu
Ładowanie pojedynczych obrazów poprzez adresy URL (jak to zwykle
czyni
ą
aplety) zajmuje du
ż
o czasu, głównie z potrzeby inicjalizacji
poł
ą
czenia HTTP.
Sytuacj
ę
mo
ż
e poprawi
ć
umieszczenie szeregu obrazów w
pojedynczym pliku (np. pliku typu JAR). Np. pasek 4 obrazów jack.gif:
Przykład programu wykre
ś
lania paska obrazów.Niech:
//
imageStrip
– to obiekt klasy
Image
reprezentuj
ą
cy pasek obrazów.
//
imageWidth
– szeroko
ść
pojedynczego obrazu w pasku.
//
imageNumber
– indeks obrazu w pasku (od 0 do
numImages
).
int stripWidth = imageStrip.getWidth(this);
int stripHeight = imageStrip.getHeight(this);
int imageWidth = stripWidth / numImages;
g.clipRect(0, 0, imageWidth, stripHeight);
g.drawImage(imageStrip, -imageNumber*imageWidth, 0, this);
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 22
8.3 D
ź
wi
ę
ki
Java Sound Engine
jest bibliotek
ą
, wyst
ę
puj
ą
c
ą
w maszynie wirtualnej,
zapewniaj
ą
c
ą
odtwarzanie 64-kanałowego d
ź
wi
ę
ku i programow
ą
syntez
ę
d
ź
wi
ę
ku według protokołu MDI.
Klipy d
ź
wi
ę
kowe mog
ą
by
ć
nast
ę
puj
ą
cych formatów:
AIFF, AU, WAV , MIDI (typu 0 lub 1) , RMF .
Dane mog
ą
by
ć
długo
ś
ci 8- lub 16-bitów. Standardowo odtwarzanie
plików audio odbywa si
ę
z cz
ę
sto
ś
ci
ą
22 kHz i w trybie 16-bitów stereo,
ale mo
ż
liwe s
ą
te
ż
tryby 8-bitów lub mono.
Java Sound API
umo
ż
liwia u
ż
ytkownikowi odczyt, odtwarzanie i zapis
d
ź
wi
ę
ku.
Usługi wy
ż
szego rz
ę
du zwi
ą
zane z multimediami (np. kompresja,
dekompresja, synchronizacja audio i wideo, transport w sieci)
zapewnia tzw.
Java Media Framework (JMF)
.
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 23
1) Odtwarzanie d
ź
wi
ę
ku w aplecie
Do
załadowania
d
ź
wi
ę
ku
z
miejsca
URL
słu
ż
y
metoda
Applet.getAudioClip.
public AudioClip getAudioClip(URL url)
public AudioClip getAudioClip(URL url, String name)
albo statyczna metoda
public final static AudioClip newAudioClip(URL url)
Obie wersje metody
getAudioClip
tworz
ą
obiekt klasy (zale
ż
nej od
kontekstu apletu) implementuj
ą
cej interfejs
AudioClip
a metoda
newAudioClip
– klasy
sun.applet.AppletAudioClip
, ale wracaj
ą
natychmiast bez wzgl
ę
du na to, czy istnieje podany adres czy te
ż
nie.
Klip b
ę
dzie ładowany przy 1-szej próbie „grania” go przez aplet.
Do natychmiastowego ładowania i „grania” słu
żą
metody apletu
play
.
Do odtwarzania klipu słu
żą
metody interfejsu
java.applet.
AudioClip
:
play, loop
i
stop
.
Ładowanie danych ma miejsce przed pierwszym odtworzeniem.
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 24
Przykład 8.6
. W aplecie
SoundApplet
pokazano odtwarzanie klipów
ró
ż
nych typów -
AU , AIFF , WAV
i
MIDI
– umieszczonych pod
wspólnym adresem.
import javax.swing.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class SoundApplet extends JApplet
implements ActionListener, ItemListener {
AppletSoundList soundList;
// Lista obiektów klipów dźwiękowych
String chosenFile;
// Nazwa aktualnie wybranego pliku dźwiękowego
AudioClip onceClip, loopClip;
// Tu będą referowane 2 obiekty klipów
...
// Korzystamy z klasy pomocniczej
// class AppletSoundList extends java.util.Hashtable,
// która zarządza listą plików dźwiękowych o podanych nazwach,
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 25
// położonych względem wspólnego globalnego URL:
soundList = new AppletSoundList(this, getCodeBase());
…
// W metodzie obsługi zdarzenia przycisków w oknie apletu
public void actionPerformed(ActionEvent event) {
// następuje m.in. pobranie klipu dźwiękowego i jego odtwarzanie
onceClip = soundList.getClip(chosenFile); //
loopClip = soundList.getClip(chosenFile);
...
onceClip.play();
// Jednokrotne odtwarzanie
...
loopClip.loop();
// Pętla odtwarzania
...
loopClip.stop();
// Zatrzymaj odtwarzanie w pętli
.
..
}
W metodach
start
i
stop
apletu nast
ę
puje wznawianie i zatrzymanie
odtwarzania pliku:
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 26
public void stop() {
onceClip.stop();
// Zatrzymanie
if (looping) {
loopClip.stop();
// Zatrzymanie
}
}
public void start() {
if (looping) {
loopClip.loop();
// Wznawianie
}
}
Pliki d
ź
wi
ę
kowe ładowane b
ę
d
ą
w w
ą
tku pobocznym, w metodzie
run()
obiektu klasy pomocniczej
SoundLoader
zamiast w metodzie
init()
apletu. Dzi
ę
ki temu ładowanie pliku nie b
ę
dzie blokowało samego
apletu.
// W pierwszej klasie pomocniczej nast
ę
puje utworzenie obiektu w
ą
tku
// dla ka
ż
dego, przez u
ż
ytkownika wybranego pliku d
ź
wi
ę
kowego:
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 27
class AppletSoundList extends java.util.Hashtable {
...
// W metodzie
startLoading
wołanej w konstruktorze obiektu klasy
// pomocniczej inicjowana jest lista obiektów klipów dźwiękowych
public void startLoading(String relativeURL) {
new AppletSoundLoader(applet, this, baseURL, relativeURL);
// Załaduje klipy i przekaże je do obiektu typu AppletSoundList
}
}
// Definicja drugiej klasy – dla w
ą
tków realizuj
ą
cych ładowanie plików
import javax.swing.*;
import java.applet.*;
import java.net.URL;
class AppletSoundLoader extends Thread {
JApplet applet;
AppletSoundList soundList;
URL baseURL;
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 28
String relativeURL;
public AppletSoundLoader(JApplet applet,
// Obiekt – aplet SoundApplet
AppletSoundList soundList,
// Obiekt - lista klipów
URL baseURL,
String relativeURL) {
this.applet = applet;
this.soundList = soundList;
this.baseURL = baseURL;
this.relativeURL = relativeURL;
setPriority(MIN_PRIORITY);
start();
// Aktywuj wątek
}
public void run() {
// Metoda run() klasy wątku AppletSoundLoader
AudioClip audioClip = applet.getAudioClip(baseURL, relativeURL);
soundList.putClip(audioClip, relativeURL);
// Dołączy plik do listy
}
}
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 29
2) Odtwarzanie d
ź
wi
ę
ku w aplikacji (
newAudioClip()
)
Aplikacje mog
ą
ładowa
ć
klipy audio z dowolnego miejsca
URL,
dzi
ę
ki
metodzie statycznej
newAudioClip
w klasie
java.applet.Applet
:
public static final AudioClip newAudioClip(URL r);
Po utworzeniu obiektu klasy implementuj
ą
cej
AudioClip
metod
ą
Applet.newAudioClip
, aplikacja korzysta z metod interfejsu
AudioClip
:
play, loop, stop
;
w celu kontroli odtwarzania d
ź
wi
ę
ku.
Przykład.
Aplikacja
SoundApplication
– posiada prawie ten sam kod co
poprzedni aplet. Jedyn
ą
zasadnicz
ą
ró
ż
nic
ą
jest zast
ą
pienie wywołania
metody
getAudioClip
przez
Applet.newAudioClip
w celu załadowania
d
ź
wi
ę
ków z
URL
.
AudioClip audioClip = Applet.newAudioClip(new URL(adresPliku));
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 30
8.4 Klasa
Graphics
Gdy ikony w AWT lub Swing-u nie wystarczaj
ą
nam dla prezentacji
grafiki mo
ż
emy skorzysta
ć
z klas
Graphics2D
lub
Graphics
.
1) Kształty
Klasa
Graphics
posiada metody dla rysowania nast
ę
puj
ą
cych
kształtów:
linia (drawLine)
prostokąt (drawRect, fillRect)
podwyższony lub obniżony prostokąt (draw3DRect, fill3DRect)
prostokąt o zaokraglonych rogach (drawRoundRect, fillRoundRect)
krzywa zamknięta (drawOval, fillOval)
łuki (drawArc, fillArc)
wielokąt (drawPolygon, drawPolyline, fillPolygon)
Np. narysowanie prostokąta:
g.drawRect(x, y, rectWidth - 1, rectHeight - 1);
Narysowanie wypełnionego obszaru prostokąta:
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 31
g.fillRect(x, y, rectWidth, rectHeight);
Uwaga: w metodzie drawRect podaje się o 1 piksel mniejszą szerokość i
wysokość, gdyż system rysuje linie pod podanym prostokątem a nie w jego
ramach.
Przykład 8.7
.
Program rysuje wypełniony
ż
ółtym kolorem prostok
ą
t w
miejscu klikni
ę
cia mysz
ą
przez u
ż
ytkownika.
GUI zawiera dwa komponenty: górny komponent jest klasy
u
ż
ytkownika RectangleArea – zawiera brzeg o dwóch stanach, tło i
ż
ółty prostok
ą
t; dolny komponent jest etykiet
ą
monitoruj
ą
c
ą
stan
programu.
Kod rysowania dla górnego komponentu:
class RectangleArea extends JPanel {
...
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 32
int rectWidth = 50;
int rectHeight = 50;
...
public RectangleArea(...) {
...
// Definiowanie brzegu dla panelu
Border raisedBevel = BorderFactory.createRaisedBevelBorder();
Border loweredBevel = BorderFactory.createLoweredBevelBorder();
Border compound = BorderFactory.createCompoundBorder
(raisedBevel, loweredBevel);
setBorder(compound);
...
}
...
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Maluj tło
// Maluj wypełniony prostokąt w miejscu wybranym przez użytkownika.
if (point != null) {
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 33
g.drawRect(point.x, point.y, rectWidth - 1, rectHeight - 1);
g.setColor(Color.yellow);
g.fillRect(point.x + 1, point.y + 1, rectWidth - 2, rectHeight - 2);
controller.updateLabel(point);
}
}
}
W metodzie paintComponent wołane są metody drawRect i fillRect w celu
narysowania prostokąta o obramowaniu 50 x 50 pikseli wypełnionego żółtym
prostokątem o rozmiarze 48 x 48 pikseli.
Uwaga: ujemne dane dla szeroko
ś
ci lub wysoko
ś
ci, albo punkt
odniesienia poło
ż
ony poza obszarem, albo zbyt du
ż
e rozmiary
prostok
ą
ta s
ą
dozwolone, ale prowadz
ą
do narysowania niepełnego
prostok
ą
ta lub całkowicie niewidocznego.
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 34
Przykład 8.8
.
Program ilustruje wszystkie kształty.
Fragment kodu rysujący podane kształty:
zmienne rectHeight i rectWidth podają rozmiar prostokąta obejmującego dla
każdego kształtu,
zmienne x i y są różne dla każdego kształtu, aby kształty nie pokrywały się;
zmienne bg i fg są typu Color – wyznaczają one kolor tła i pióra.
Color fg3D = Color.lightGray;
...
// Metoda: drawLine(x1, y1, x2, y2)
g.drawLine(x, y+rectHeight-1, x + rectWidth, y);
...
// Metoda: drawRect(x, y, w, h)
g.drawRect(x, y, rectWidth, rectHeight);
...
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 35
// Metoda: draw3DRect(x, y, w, h, raised)
g.setColor(fg3D);
g.draw3DRect(x, y, rectWidth, rectHeight, true);
g.setColor(fg);
...
// Metoda: drawRoundRect(x, y, w, h, arcw, arch)
g.drawRoundRect(x, y, rectWidth, rectHeight, 10, 10);
...
// Metoda: drawOval(x, y, w, h)
g.drawOval(x, y, rectWidth, rectHeight);
...
// Metoda: drawArc(x, y, w, h, startAngle, arcAngle)
g.drawArc(x, y, rectWidth, rectHeight, 90, 135);
...
// Metoda: drawPolygon(xPoints, yPoints, numPoints)
// Rysuje krzywą zamkniętą
int x1Points[] = {x, x+rectWidth, x, x+rectWidth};
int y1Points[] = {y, y+rectHeight, y+rectHeight, y};
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 36
g.drawPolygon(x1Points, y1Points, x1Points.length);
...
// Metoda: drawPolyline(xPoints, yPoints, numPoints)
// Rysuje krzywą otwartą
int x2Points[] = {x, x+rectWidth, x, x+rectWidth};
int y2Points[] = {y, y+rectHeight, y+rectHeight, y};
g.drawPolyline(x2Points, y2Points, x2Points.length);
...
// Metoda: fillRect(x, y, w, h)
g.fillRect(x, y, rectWidth, rectHeight);
...
// Metoda: fill3DRect(x, y, w, h, raised)
g.setColor(fg3D);
g.fill3DRect(x, y, rectWidth, rectHeight, true);
g.setColor(fg);
...
// Metoda: fillRoundRect(x, y, w, h, arcw, arch)
g.fillRoundRect(x, y, rectWidth, rectHeight, 10, 10);
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 37
...
// Metoda: fillOval(x, y, w, h)
g.fillOval(x, y, rectWidth, rectHeight);
...
// Metoda: fillArc(x, y, w, h, startAngle, arcAngle)
g.fillArc(x, y, rectWidth, rectHeight, 90, 135);
...
// Metoda: fillPolygon(xPoints, yPoints, numPoints)
int x3Points[] = {x, x+rectWidth, x, x+rectWidth};
int y3Points[] = {y, y+rectHeight, y+rectHeight, y};
g.fillPolygon(x3Points, y3Points, x3Points.length);
...
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 38
2) Rysowanie tekstu
Funkcjonalno
ść
dla rysowanie tekstu w AWT zapewniaj
ą
klasy
Graphics, Font, FontMetrics
.
W miar
ę
mo
ż
liwo
ś
ci nale
ż
y korzysta
ć
z komponentów stworzonych dla
reprezentacji informacji tekstowej.
W klasie
Graphics
zdefiniowano trzy metody rysowania tekstu:
drawBytes, drawChars, drawString.
Np.
g.drawString("Hello World!", x, y);
Argumenty (liczby całkowite) x, y – pozycja lewego dolnego rogu tekstu
(y wyznacza bazow
ą
lini
ę
tekstu).
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 39
Klasa FontMetrics -
umożliwia zmianę domyślnej czcionki.
Przykład 8.9
. Program jest modyfikacją poprzedniego programu (8.8)-
wykorzystano obiekt klasy FontMetrics dla zmiany rozmiaru czcionki tak,
aby najdłuższy napis („drawRoundRect”) zmieścił się w obszarze dla
pojedynczego kształtu.
boolean fontFits = false;
Font currentFont = biggestFont;
FontMetrics currentMetrics = getFontMetrics(currentFont);
int size = currentFont.getSize();
String name = currentFont.getName();
int style = currentFont.getStyle();
while (!fontFits) {
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 40
if ( (currentMetrics.getHeight() <= maxCharHeight)
&& (currentMetrics.stringWidth(longString) <= xSpace)) {
fontFits = true;
} else {
if (size <= minFontSize) {
fontFits = true;
} else { currentFont = new Font(name, style, --size);
currentMetrics = getFontMetrics(currentFont);
}
}
Obiekt klasy FontMetrics udostępnia następującą informację o rozmiarach
danej czcionki:
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 41
Metody klasy FontMetrics
informujące o pionowych rozmiarach:
int getAscent()
int getMaxAscent()
Pierwsza metoda podaje liczbę pikseli pomiędzy linią górną a bazową. Druga
- maksymalną odległość dla najwyższych znaków.
int getDescent()
int getMaxDescent()
Pierwsza metoda podaje liczbą pikseli pomiędzy linią bazową a linią dolną.
Druga – maksymalna odległość dla najwyższych znaków.
int getHeight();
Metoda podaje liczbą pikseli pomiędzy linią bazową wiersza
tekstu a linią bazową następnego wiersza tekstu.
int getLeading()
; Metoda podaje liczbą pikseli odstępu pomiędzy sąsiednimi
wierszami tekstu – pomiędzy linią dolną jednego wiersza a linią dolną
nastepnego. Do oznaczenia wysokości czcionki stosuje się miarę „punktową”
– 1 punkt to ok. 1/72 cala.
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 42
Metody klasy
FontMetrics
informujące o rozmiarach w poziomie dla czcionki
(podają one szerokość czcionki z uwzględnieniem odstępu):
int getMaxAdvance()
Pełna szerokość (w pikselach) najszerszego znaku czcionki.
int bytesWidth(byte[], int, int)
Pełna szerokość tekstu - wycinka tablicy (1-szy argument) od podanego
indeksu (2-gi argument) i o podanej liczbie bajtów (3-ci argument).
int charWidth(int)
int charWidth(char)
; Pełna szerokość podanego znaku.
int charsWidth(char[], int, int)
Pełna szerokość napisu – wycinka tablicy znaków.
int stringWidth(String)
; Pełna szerokość podanego napisu.
int[] getWidths()
Pełna szerokość każdego z pierwszych 256 znaków czcionki.
8. Multimedia.
W. Kasprzak: Programowanie zdarzeniowe
8 - 43
3) Klasa
Graphics2D
Jest to znacznie bogatsza w kształty geometryczne klasa graficzna
wprowadzona w Java 2. Umożliwia ona:
rysowanie linii o dowolnej grubości;
wypełnianie kształtów gradientami i teksturami;
przesuwanie, obracanie i skalowanie oraz łączenie tekstu i grafiki;
komponowanie przesłaniania tekstu i grafiki;
zapamiętywanie obrazów i operacje na obrazach.
Np.