Predavanje br. index|1|2|3|4|5|6|7|8|9|10|11|12|13|14|HOME
Što je izbornik? – klase izbornika – kreiranje izbornika –
primjer izbornika – događaji vezani uz izbornike – izborničke kratice – padajući
izbornici (popup menus) – slike – kamo staviti slike? – učitavnje slika –
crtanje slika – uporaba povratne vrijednosti metoda drawImage() – primjer
crtanja slika – promjena veličine slike – ustanovljavanje veličine slike – paket
java.awt.image – Sučelja ImageProducer, ImageObserver, ImageConsumer – sučelje
ImageConsumer – čekanje na učitavanje slike – prekrivanje metode imageUpdate() –
što je zapravo slika? – operator << - kreiranje slika – primjer kreiranja
slika – metoda getRGB() – pretapanje boja – filtriranje slika – klasa
RGBImageFilter – primjer plavog filtra – primjer filtra sivih tonova – filtri
koji ovise o položaju – filtri koji ovise o adjungiranim pixelima – audio –
kontinuirana izvedba
Java omogućuje postavljanje izbornika na frameove (dijalozima se izbornici ne mogu dodavati). Za applete to i nije tako bitno, ali u aplikacijama je najčešće nužno.
Izbornici su sastavljeni od tri hijerarhijska elementa Prvi element je izbornička letvica (menu bar) i sastoji se od različitih izbornika. Nalazi se na gornjem rubu ekrana kod Macintosha ili na gornjem rubu prozora kod Windowsa ili Motifa.
Svaka izbornička letvica sadrži bar jedan izbornik (menu). Izbornici su organizirani poi temama. Često susrećemo File, Edit i tako dalje.
Svaki izbornik sadrži bar jednu opciju (menu item). Opcije su obično pojedinačne akcije kao Open, Print, Cut ili Copy. Opcije nisu prikazane dok izbornik nije aktivan. Dva ili više izbornika ne mogu biti istodobno aktivni.
Na primjer ovaj Edit izbornik ima onemogućenu Undo opciju nakon koje dolazi separator, a iz njega omogućene opcije Cut, Copy, paste i Clear, zatim još jedan separator pa omogućena opcija Select All.
Paket AWT sadrži nekoliko glavnih klasa za upravljanje izbornicima:
Da biste izbornike koristili u svojim aplikacijama, bit će
vam potreban bar jedan primjerak iz klase MenuBar
sa
jednim ili više primjeraka klase Menu
, a za
svakog nekoliko primjeraka MenuItem
.
Izbornici iz klase PopupMenu
se pojavljuju kao samostalni element.
Klasa java.awt.MenuComponent
je zadnja nadklasa svih ovih klasa, a ona je opet podklasa od java.lang.Object
.
Prema tome, izborničke letvice, izbornici i opcije nisu komponente i ne
mogu se dodavati kontejnerima na uobičajeni način.
java.lang.Object
|
+--java.awt.MenuComponent
|
+--java.awt.MenuBar
|
+--java.awt.MenuItem
|
+--java.awt.Menu
|
+--java.awt.PopupMenu
Primijetite
da su MenuBar
i
MenuItem
podklase od MenuComponent
.
Menu
je
podklasa od MenuItem
(ovo
zvuči malo neobično, ali izbornike je zaista opcija, samo se dodaje izborničkoj
letvici). Nadalje, MenuBar
implementira sučelje java.awt.MenuContainer
.
Izbornike je poželjno potpuno izgraditi prije nego ih prikažete. Tipični redosljed je ovakav:
MenuBar
.
Menu
.
Menu
.
MenuBar
objektu tipa Frame
.
Konstruktori
koji su vam potrebni su jednostavni. Novi objekt tipa MenuBar
kreirat ćete ovako:
MenuBar myMenubar = new MenuBar();
Za
kreiranje novog objekta tipa Menu
koristite
konstruktor Menu(String
title)
. Dodajte mu naslov koji želite dati izborniku. Na primjer,
za kreiranje izbornika File i Edit, napravite:
Menu fileMenu = new Menu("File");
Menu editMenu = new Menu("Edit");
Opcije,
MenuItem
are
kreiraju se slično, pomoću konstruktora MenuItem(String
menutext)
. Dajte mu potreban naslov, na primjer:
MenuItem Cut = new MenuItem("Cut");
Objekte
tipa MenuItem
kreirate unutar odgovarajućih objekata tipa Menu
kojima
pripadaju, isto kao što ste komponente kreirali unutar odgovarajućih
razmještaja. Izbornici imaju add()
metode koje kao argument uzimaju objekte tipa MenuItem
. Evo
kako biste napravili Edit izbornik i dodali mu oipcije Undo,
Cut, Copy, Paste, Clear i Select All:
Menu editMenu = new Menu("Edit");
editMenu.add(new MenuItem("Undo"));
editMenu.addSeparator();
editMenu.add(new MenuItem("Cut"));
editMenu.add(new MenuItem("Copy"));
editMenu.add(new MenuItem("Paste"));
editMenu.add(new MenuItem("Clear"));
editMenu.addSeparator();
editMenu.add(new MenuItem("Select All"));
Metoda
addSeparator()
dodaje horizontalnu crtu preko izbornika. Koristi se za logičko razdvajanje
funkcija na izborniku.
Kad
kreirate izbornike, dakle objekte tipa Menu
, dodat
ćete ih letvici, objektu tipa MenuBar
koristeći MenuBar
ovu
metodu add(Menu
m)
ovako:
myMenubar.add(fileMenu);
myMenubar.add(editMenu);
Konačno,
kad je MenuBar
gotov,
dodat ćete ga okviru, dakle objektu tipa Frame
koristeći se frameovom metodom setMenuBar(MenuBar
mb)
. Ako imate Frame f
onda
bi to izgledalo ovako:
f.setMenuBar(myMenuBar);
Aplikacija
može imati mnogo opcija, čak i po više stotina. Sve njih staviti u init()
metodu
bilo bi nepraktično. Uobičajeno je kreirati odvojene metode koje grade svaki
pojedini izbornik i dodaju ih izborničkoj letvici. Sljedeći program kreira dva
standardna izbornika, File i Edit.
import java.applet.*;
import java.awt.*;
public class MenuTester extends Applet {
public void init () {
Frame f = new Frame("Prozor s izbornicima");
f.add("Center", new Label("Pogledajte izbornike", Label.CENTER));
f.setSize(this.getSize().width, this.getSize().height);
f.setLocation(320,240);
MenuBar myMenuBar = new MenuBar();
this.makeFileMenu(myMenuBar);
this.makeEditMenu(myMenuBar);
f.setMenuBar(myMenuBar);
f.show();
}
void makeEditMenu(MenuBar mb) {
Menu editMenu = new Menu("Edit");
editMenu.add("Undo");
editMenu.addSeparator();
editMenu.add("Cut");
editMenu.add("Copy");
editMenu.add("Paste");
editMenu.add("Clear");
mb.add(editMenu);
}
void makeFileMenu(MenuBar mb) {
Menu fileMenu = new Menu("File");
fileMenu.add("New");
fileMenu.add("Open...");
fileMenu.addSeparator();
fileMenu.add("Close");
fileMenu.add("Save");
fileMenu.add("Save As...");
fileMenu.addSeparator();
fileMenu.add("Page Setup...");
fileMenu.add("Print");
fileMenu.addSeparator();
fileMenu.add("Quit");
mb.add(fileMenu);
}
}
<APPLET
CODE="MenuTester.class"
CODEBASE="http://student.math.hr/~vedris/java/classes"
WIDTH=200
HEIGHT=100>
</APPLET>
Kad korisnik odabere opciju, izbornik lansira objekt tipa java.awt.event.ActionEvent. Njega može pokupiti bilo koji actionListener, dakle objekt iz klase koja implementira sučelje java.awt.event.ActionListener koji smo registrirali uz opciju, dakle objekt tipa MenuItem. Action komanda koju možemo pročitati metodom getActionCommand() sadržat će tekst opcije.
Na
primjer, sljedeći applet stavlja tekst odabrane opcije u tekstualno polje
theChoice
.
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class ActiveMenuTester extends Applet
implements ActionListener
{
TextField theChoice = new TextField(20);
public void init () {
Frame f = new Frame("Prozor s izbornicima ");
f.add("North", new Label("Pogledajte izbornike ", Label.CENTER));
f.add("South", theChoice);
f.setSize(300, 200);
f.setLocation(220,240);
MenuBar myMenuBar = new MenuBar();
this.makeFileMenu(myMenuBar);
this.makeEditMenu(myMenuBar);
f.setMenuBar(myMenuBar);
f.addWindowListener(new WindowCloser());
f.show();
}
protected void addItem(Menu m, String s) {
MenuItem mi = new MenuItem(s);
mi.addActionListener(this);
m.add(mi);
}
protected void makeEditMenu(MenuBar mb) {
Menu editMenu = new Menu("Edit");
this.addItem(editMenu, "Undo");
editMenu.addSeparator();
this.addItem(editMenu, "Cut");
this.addItem(editMenu, "Copy");
this.addItem(editMenu, "Paste");
this.addItem(editMenu, "Clear");
mb.add(editMenu);
}
protected void makeFileMenu(MenuBar mb) {
Menu fileMenu = new Menu("File");
this.addItem(fileMenu, "New");
this.addItem(fileMenu, "Open...");
fileMenu.addSeparator();
this.addItem(fileMenu, "Close");
this.addItem(fileMenu, "Save");
this.addItem(fileMenu, "Save As...");
fileMenu.addSeparator();
this.addItem(fileMenu, "Page Setup...");
this.addItem(fileMenu, "Print");
fileMenu.addSeparator();
this.addItem(fileMenu, "Quit");
mb.add(fileMenu);
}
public void actionPerformed(ActionEvent e) {
theChoice.setText(e.getActionCommand());
}
class WindowCloser extends WindowAdapter {
public void windowClosing(WindowEvent e) {
Window w = (Window) e.getSource();
w.setVisible(false);
w.dispose();
}
}
}
<APPLET
CODE="ActiveMenuTester.class"
CODEBASE="http://student.math.hr/~vedris/java/classes"
ARCHIVE="ActiveMenuTester.jar"
WIDTH=200
HEIGHT=100>
</APPLET>
Izborničke kratice, poznate i pod nazivom akceleratori ili tipovni ekvivalenti naredbe, obično ne ubrzavaju ništa, ali budući da ih korisnici vole, komercijalne aplikacije ih trebaju sadržavati.
Klasa
java.awt.MenuShortcut
predstavlja takve kratice u Javi. Ima sljedeće konstruktore:
public MenuShortcut(int key)
public MenuShortcut(int key, boolean useShiftModifier)
U
oba slučaja argument key
je zapravo
keycode tipke koja će aktivirati tu opciju.
Ako
je useShiftModifier
postavljen na true
, onda
tipka shift mora biti pritisnuta da bi kratica aktivirala opciju. Po
pretpostavci, useShiftModifier
je false
.
Da
biste opciji izbornika pridružili kraticu, pozovite metodu setShortcut()
iz klase java.awt.MenuItem
.
Na primjer,
MenuShortcut pShortcut = new MenuShortcut(KeyEvent.VK_P);
MenuItem mi = new MenuItem("Print...");
mi.setShortcut(pShortcut);
Kraticu
možete definirati i pomoću odgovarajućeg konstruktora MenuItem()
ovako:
MenuShortcut pShortcut = new MenuShortcut(KeyEvent.VK_P);
MenuItem mi = new MenuItem("Print...", pShortcut);
Kraticu
možete ukloniti pomoću metode deleteShortcut()
iz klase java.awt.MenuItem
,
na primjer:
mi.deleteShortcut();
Već
smo se susreli s klaslom already encountered the java.awt.Choice
čiji se objekti ponašaju kao padajući izbornici, no imaju fiksnu lokaciju.
Klasa
java.awt.PopupMenu
class, on the other hand, is activated when the user holds the right mouse
button or otherwise indicates that they want to pop up a menu. Typically this is
used for context sensitive menus.
Klasa
java.awt.PopupMenu
je podklasa od java.awt.Menu
.
Uglavnom je koristite kao i obične izbornike. Stavke se dodaju metodom
add()
,
a na korisnikove izbore odgovara se pomoću ActionListenera
instaliranog na MenuItem.
Na primjer, da biste napravili padajući izbornik sa raznim URL-ovima, možete
postupiti ovako:
PopupMenu pm = new PopupMenu();
MenuItem mi = new MenuItem("http://www.javasoft.com/");
mi.addActionListener(URLActionListener);
pm.add(mi);
mi = new MenuItem("http://home.netscape.com/");
mi.addActionListener(URLActionListener);
pm.add(mi);
mi = new MenuItem("http://metalab.unc.edu/javafaq");
mi.addActionListener(URLActionListener);
pm.add(mi);
mi = new MenuItem("http://www.roaster.com/news/");
mi.addActionListener(URLActionListener);
pm.add(mi);
Međutim,
padajući izbornici ne pripadaju nekom određenom MenuBar
u.
Umjesto toga, oni se dodaju komponenti. Na primjer, za dani okvir, Frame f
,
instalirali biste PopupMenu pm
u
taj okvir tako da ga proslijedite metodi add()
iz klase java.awt.Component,
ovako:
f.add(pm);
Primijetite
da to nije ona ista add()
metoda koju koristite za dodavanje komponente okviru.
Točan
način pokretanja padajućih izbornika ovisi o platformi. Na primjer, na
Windowsima se PopupMenu
pokreće podizanjem desne tipke miša. Na Motifu se pokreće pritiskanjem desne
tipke miša. Neovisno o egzaktnoj sekvenci događaja koja pokreće padajući
izbornik, kad korisnik odabere neku opciju, odnosno kad odabere neki MenuItem
,
lansira se ActionEvent
kojeg treba uhvatiti odgovarajući listener registriran uz tu stavku.
Objekt
tipa PopupMenu
se
može ukloniti iz komponente tako da ga se proslijedi komponentinoj metodi
remove()
,
na primjer ovako:
f.remove(pm);
Uz jednu komponentu može biti instaliran najviše jedan padajući izbornik. Ako je instaliran uz kontejner, onda će trigeri iz komponenata koje se nalaze u tom kontejneru također pokretati padajuće izbornike pod uvjetom da kontejner nema svoj vlastiti padajući izbornik.
Slike
u Javi su bitmapirane GIF ili JPEG datoteke koje mogu sadržavati proizvoljnu
sliku. Možete ih kreirati bilo kojim programom koji je u stanju napraviti GIF
ili JPEG format. Jednom kad su učitane u Javu, slike postaju instance apstraktne
klase java.awt.Image
.
Ta klasa ima sljedeće (apstraktne) metode:
public abstract int getWidth(ImageObserver observer)
public abstract int getHeight(ImageObserver observer)
public abstract ImageProducer getSource()
public abstract Graphics getGraphics()
public abstract Object getProperty(String name, ImageObserver observer)
public Image getScaledInstance(int width, int height, int hints)
public abstract void flush()
Najveći
dio posla oko slika obavlja se ipak u drugim klasama, posebno u java.awt.Graphics
,
java.awt.Component
,
i java.awt.Toolkit
.
Metodama iz tih klasa prosljeđujete objekt tipa Image
da biste
učitali i prikazali sliku.
Skuje koje prikazuju Java appleti učitavaju se s weba preko URL-a koji pokazuje na datoteku sa slikom. Applet koji prikazuje sliku mora poznavati taj URL. Slike mogu biti spremljene na web poslužitelju, lokalnom disku ili bilo gdje kamo applet može stići pomoću URL-a. Pazite da slike stavljate tamo gdje ih applet može dohvatiti. URL koji pokazuje na vaš lokalni disk može biti od koristi dok razvijate applet, ali ne može poslužiti nekome tko dolazi preko weba.
Tipično, slike se stavljaju u isti direktorij u kojem se nalazi applet ili u onaj u kojem se nalazi HTML document. Iako to nije obavezno, stavljanje slika na neku od tih lokacija je obično praktično. Stavite sliku zajedno sa appletovom class datotekom ako će se ona koristiti sa svim instancama appleta. Ili je stavite u HTML direktorij ako će razne instance appleta koristiti razne slike. Treća alternativa je staviti sve slike na zajedničku lokaciju i koristiti oznaku <PARAM> za dojavljivanje mjesta gdje se one nalaze.
Ako znate točan URL slike koju želite učitati, možete to učiniti ovako:
URL imageURL = new URL("http://student.math.hr/~vedris/java/images/sun.jpg");
Image img = getImage(imageURL);
To se može zapisati i na kraći način:
Image img = getImage(new URL( "http://student.math.hr/~vedris/java/images/sun.jpg"));
Metoda
getImage()
je iz klase java.applet.Applet
pa ona funkcionira unutar appleta. Izvan appleta možete koristiti metodu getImage()
iz klase java.awt.Toolkit.
URL imageURL = new URL("http://student.math.hr/~vedris/java/images/sun.jpg");
Image img = Toolkit.getDefaultToolkit.getImage(imageURL);
Ako
ne znate točan URL slike, ali znate njeno ime i znate da se nalazi u istom
direktoriju kao i applet, koristit ćete appletovu metodu getCodeBase()
koja će vam vratiti URL appletovog direktorija:
Image img = getImage(getCodeBase(), "sun.jpg");
Konačno,
ako je slika u istom direktoriju kao HTML datoteka, koristit ćete appletovu
metodu getDocumentBase()
koja će vratiti URL direktorija HTML stranice:
Image img = getImage(getDocumentBase(), "sun.jpg");
Ako se slika učitava sa Interneta, to može potrajati. U pravilu ne morate voditi posebnog računa o tom i možete iscrtati sliku čim ste je povezali sa URL-om. Java će sama, bez vaše intervencije, prikazati sliku čim pristigne dovoljno podataka za to.
Sve
slike koje applet treba učitajte već u init()
metodi.
Posebno, nemojte ih učitavati u paint()
metodi
jer će se tada ponovno učitavati svaki put kad applet napravi repaint(),
što će drastično sniziti performanse.
Sliku
koja se koristi u sljedećim primjerima možete skinuti sa http://student.math.hr/~vedris/java/images/sun.jpg
.
Jednom
kad ste sliku učitali s nekog URL-a, relativno je jednostavno iscrtati je. To
ćete učiniti u paint()
metodi, koristeći neku od metoda drawImage()
iz
klase java.awt.Graphics
,
npr.
public boolean drawImage(Image img, int x, int y, ImageObserver io)
Ovdje
je img
member
klase Image
koji je
u tom trenutku već učita. Atributi x
i
y
su koordinate lijevog gornjeg ugla slike, dok je io
instanca
klase koja implementira sučelje java.awt.image.ImageObserver.
To
sučelje propisuje kako Java rukuje asinhronim ažuriranjem slike. Ono je
implementirano u klasi java.awt.Component
pa možete za sada jednostavno staviti ključnu riječ this u metodu drawImage(),
čime ćete naznačiti da je sam applet taj koji će obaviti poslove ažuriranja
slike.
Metoda
paint()
ne
radi ništa drugo osim crtanja slike, počevši od lijevog gornjeg ugla i može
izgledati na primjer ovako:
public void paint(Graphics g) {
g.drawImage(img, 0, 0, this);
}
Pretpostavljamo
da atribut img
referencira objekt koji je prethodno već bio inicijaliziran.
drawImage()
Metoda
drawImage()
vraća vrijednost tipa boolean
. Iako
se na nju često zaboravlja, ona vam kaže da li je slika uspješno nacrtana ili
nije. Ako jest, metoda će vratiti true
, u
protivnom false
.
Na primjer, sljedeći applet učitava sliku s mreže. Dok se slika učitava, applet će na njenom mjestu prikazivati tekst "Slika se ucitava. Molim, pricekajte". Kad slika bude učitana u potpunosti, applet će je prikazati.
import java.awt.*;
import java.applet.*;
import java.awt.image.*;
public class ImageDisplay extends Applet {
Image picture;
public void init() {
this.picture = this.getImage(this.getCodeBase(), "sun.jpg");
}
public void paint(Graphics g) {
if(!g.drawImage(this.picture, 0, 0, this)) {
g.drawString("Slika se ucitava. Molim, pricekajte", 25, 50);
}
}
}
<APPLET
CODE="ImageDisplay.class"
CODEBASE="http://student.math.hr/~vedris/java/classes/ImageProcessing"
WIDTH=435
HEIGHT=300>
</APPLET>
U sljedećem primjeru slika će se iscrtati ako je njeno ime dobiveno iz oznake <PARAM>, a u protivnom bit će ispisana poruka "nema slike! ".
import java.awt.*;
import java.applet.*;
public class DisplayImage extends Applet {
private Image picture;
public void init() {
String filename = this.getParameter("imagefile");
if (filename != null) {
this.picture = this.getImage(this.getCodeBase(), filename);
}
}
public void paint(Graphics g) {
if (this.picture != null) {
g.drawImage(this.picture, 0, 0, this);
}
else {
g.drawString("Nema slike!", 20, 20);
}
}
}
<APPLET
CODE="DisplayImage.class"
CODEBASE="http://student.math.hr/~vedris/java/classes/ImageProcessing"
WIDTH=435
HEIGHT=300>
<PARAM
NAME="imagefile" VALUE="sun.jpg">
</APPLET>
Ne
morate se ograničiti na crtanje slike samo u njenoj prirodnoj veličini. Sljedeća
varijacija paint()
metode
dopušta vam određivanje širine i visine slike, slično primjeru MagnifyImage
iz predavanja o appletima (peto predavanje).
public boolean drawImage(Image img, int x, int y,
int width, int height, ImageObserver io)
import java.awt.*;
import java.applet.Applet;
public class MagnifyImageDisplay extends Applet {
private Image picture;
private double scalefactor;
public void init() {
String filename=this.getParameter("imagefile");
if (filename != null) {
this.picture = this.getImage(getCodeBase(), filename);
}
try {
scalefactor = Double.valueOf(
this.getParameter("scalefactor")).doubleValue();
}
catch (Exception e) {
this.scalefactor = 1.0;
}
}
public void paint (Graphics g) {
if (this.picture != null) {
int width = picture.getWidth(this);
int height = picture.getHeight(this);
int scaleWidth = (int) (width * scalefactor);
int scaleHeight = (int) (height * scalefactor);
g.drawImage(picture, 0, 0, scaleWidth, scaleHeight, this);
}
else {
g.drawString("Missing imagefile PARAM element in HTML page", 10, 10);
}
}
}
<APPLET
CODE="MagnifyImageDisplay.class"
CODEBASE="http://student.math.hr/~vedris/java/classes/ImageProcessing"
WIDTH=435
HEIGHT=300>
<PARAM
NAME="imagefile" VALUE="sun.jpg">
<PARAM
NAME="scalefactor" VALUE="0.5">
</APPLET>
Ako pravokutnik u koji ucrtavate sliku nije proporcionalan veličini slike, onda ona može biti izobličena.
Da
bismo izbjegli nepravilno skaliranje koje dovodi do izobličenja, koristit ćemo
metode getHeight()
i getWidth()
iz klase java.awt.Image
kako bismo doznali veličinu slike. Tada je možemo, ako je potrebno, skalirati
proporcionalno. Na primjer, ovako biste smanjili sliku na jednu četvrtinu
izvorne širine i visine:
g.drawImage(img, 0, 0, img.getWidth(this)/4, img.getHeight(this)/4, this);
Pogledajmo primjer koji crta sliku u pravoj veličini bez obzira na veličinu appletovog pravokutnika:
import java.awt.*;
import java.applet.Applet;
public class FillWithImage extends Applet {
private Image picture;
public void init() {
String filename = this.getParameter("imagefile");
if (filename != null) {
this.picture = this.getImage(this.getCodeBase(), filename);
}
}
public void paint (Graphics g) {
if (this.picture != null) {
g.drawImage(this.picture, 0, 0,
this.getSize().width, this.getSize().height, this);
}
else {
g.drawString("Nedostaje PARAM imagefile u HTML dokumentu", 10, 10);
}
}
}
<APPLET
CODE="FillWithImage.class"
CODEBASE="http://student.math.hr/~vedris/java/classes/ImageProcessing"
WIDTH=700
HEIGHT=500>
<PARAM
NAME="imagefile" VALUE="sun.jpg">
</APPLET>
java.awt.image
Paket
java.awt.image
sadrži klase i sučelja koje omogućuju kreiranje novih slika from scratch
umjesto učitavanja i modificiranja već postojećih slika.
Za nas će biti zanimljiva sljedeća sučelja i sljedeće klase:
java.awt.image.AreaAveragingScaleFilter
java.awt.image.ColorModel
java.awt.image.CropImageFilter
java.awt.image.DirectColorModel
java.awt.image.FilteredImageSource
java.awt.image.ImageFilter
java.awt.image.IndexColorModel
java.awt.image.MemoryImageSource
java.awt.image.PixelGrabber
java.awt.image.RGBImageFilter
java.awt.image.ReplicateScaleFilter
Kad
pozovete appletovu metodu getImage()
,
slika se ne može odmah pojaviti, već mora proći neko vrijeme da se ona učita.
Veće slike učitavat će se duže. Ako se slika učitava sa Interneta, to može
potrajati još duže.
Umjesto
čekanja da se slika učita, metoda getImage()
se
vraća odmah, možda i prije nego što se veza s udaljenim računalom uopće
uspostavila. Ona vraća objekt tipa Image
, ali on
inicijalno možda ne sadrži nikakve podaatke. Razne metode u paketu AWT koje
koriste slike ponašaju se u skladu s tim. Na primjer, ako je samo gornja
polovica slike dostupna u trenutku kad se pozove neka od metoda drawImage()
iz klase Graphics,
bit će prikazana samo ta gornja polovica.
U
međuvremenu, u pozadini, u odvojenom threadu, neki ImageProducer, dakle
objekt iz klase koja implementira sučelje java.awt.image.ImageProducer
,
popunjava sliku pixelima što brže može. Kako više pixela postane dostupno, bar
za jedan redak, on će obavijestiti o tome sve ImageObservere koji su
registrirani da imaju interes za tu sliku.
Kako
neki ImageObserver
registrira svoj interes za sliku? Tako da ga se proslijedi metodi koja nešto
radi sa slikom. Na primjer, sjetite se da metode drawImage()
,
iz klase Graphics,
te getWidth()
i getHeight()
iz klase Image
primaju između ostaloga i argument tipa ImageObserver
.
Klasa
java.awt.Component
implementira sučelje ImageObserver
pa to čine i sve njene podklase. To znači da objekti tipa Button, TextArea,
CheckBox, Panel, Applet, i drugi mogu igrati ulogu ImageObserver
a.
Ipak, u pravilu ćete koristiti onu komponentu koja u tom trenutku pokušava
crtati sliku.
Sučelje
ImageObserver
propisuje samo jednu metodu, imageUpdate()
:
public abstract boolean imageUpdate(Image img, int infoflags,
int x, int y, int width, int height)
Sučelje
ImageProducer
koristi tu metodu da bi obavijestio ImageObserver
a
da je pristiglo još podataka o slici pa se njen prikaz može osviježiti.
Sučelje
java.awt.image.ImageConsumer
je manje obično. Dok ImageProducer
nekom ImageObserver
u
samo kaže da je dio slike spreman, dotle zainteresiranom ImageConsumer
u
daje stvarne podatke o slici. Sučelje ImageConsumer
propisuje sljedeće metode:
public abstract void setDimensions(int width, int height)
public abstract void setProperties(Hashtable props)
public abstract void setColorModel(ColorModel model)
public abstract void setHints(int hintflags)
public abstract void setPixels(int x, int y, int width, int height,
ColorModel model, byte[] pixels, int off, int scansize)
public abstract void setPixels(int x, int y, int width, int height,
ColorModel model, int[] pixels, int off, int scansize)
public abstract void imageComplete(int status)
Sučelje
java.awt.image.ImageObserver
omogućuje vam nadziranje procesa učitavanja, tako da možete informirati
korisnika o statusu učitavanja i početi koristiti sliku čim bude spremna.
Kad
neki ImageProducer
primi dodatne podatke za neku sliku, pozvat će metodu imageUpdate()
kod svakog registriranog klijenta. Pretpostavljena (default) imageUpdate()
metoda u klasi java.awt.Component
osvježuje (repaints) prikaz komponente kad se slika promijeni.
Ipak,
varijable koje su postavljene pomoću metoda kao što getHeight()
ili getWidth()
ne ažuriraju se automatski po pozivu metode imageUpdate()
.
Morate ih, dakle, sami ažurirati kod promjene slike ako je potrebno.
Točna
količina podataka koju neki ImageProducer
dobije prije nego pozove metodu imageUpdate()
je nepredvidljiva.
imageUpdate()
Pretpostavljena imageUpdate()
metoda iz klase java.awt.Component
osvježuje prikaz komponente kad se slika promijeni. Možete je, međutim, prekriti
tako da radi nešto drugo. Na primjer, sljedeći applet ispisuje poruku na
statusnoj liniji browsera dok prati učitavanje slike.
import java.awt.*;
import java.applet.*;
import java.awt.image.*;
public class ImageStatus extends Applet
implements ImageObserver
{
private Image picture;
public void init() {
String filename = this.getParameter("imagefile");
if (filename != null) {
this.picture = this.getImage(this.getCodeBase(), filename);
}
}
public void paint(Graphics g) {
if (this.picture != null) {
g.drawImage(this.picture, 0, 0, this);
}
else {
g.drawString("Nema slike", 20, 20);
}
}
public boolean imageUpdate(Image img, int infoflags, int x, int y,
int width, int height) {
if ((infoflags & ImageObserver.ALLBITS) != 0) {
showStatus("Slika ucitana");
this.repaint();
return false;
}
else {
showStatus("x: " + x + " y: " + y + " sirina: " + width
+ " visina: " + height);
this.repaint();
}
return true;
}
}
<APPLET
CODE="ImageStatus.class"
CODEBASE="http://student.math.hr/~vedris/java/classes/ImageProcessing"
WIDTH=435
HEIGHT=300>
<PARAM
NAME="imagefile" VALUE="sun.jpg">
</APPLET>
Slika je pravokutna mreža pixela. Ona ima konačnu širinu i visinu koje se mogu izraziti brojem pixela. Svaki pixel je kvadratić koji ima fiksnu veličinu na danom ekranu. Veličina pixela može ovisiti o ekrani i računalu.
Svaki pixel ima neku boju. Boja je 32-bitni integer. Prvih osam bitova određuje udio crvene boje, drugih osam udio zelene, a trećih osam udio plave boje. Preostalih osam pixela određuje transparentnost pixela.
|
|
|
| ||||||||||||||||||||||||||||||||
Transparency |
Red |
Green |
Blue |
Svaka od ovih vrijednosti može se interpretirati kao neoznačeni byte između 0 i 255. Unutar neke boje, veći brojevi označavaju svijetliju (brighter), odnosno intenzivniju boju. Tako crvena boja vrijednosti 0 nije uopće crvena, dok je ona koja ima vrijednost 255 intenzivno crvena.
Trenutačno su dostupna samo dva stupnja transparencije: potpuno neprozirno (255) i potpuno prozirno (0). Vrijednosti od 1 do 254 interpretiraju se kao potpuno prozirno.
Različite boje dobijaju se miješanjem osnovnih triju boja u različitim omjerima. Na primjer, umjereno siva je zapravo 127 crveno (red), 127 zeleno (green) i 127 plavo (blue):
255 |
127 |
127 |
127 |
Čista bijela je 255 red, 255 green, 255 blue:
255 |
255 |
255 |
255 |
Čista crvena je 255 red, 0 green, 0 blue:
255 |
255 |
0 |
0 |
Svijetlo krem je 255 red, 231 green, 187 blue:
255 |
255 |
231 |
187 |
<<
Operator
<<
pomiče bitove cijelih brojeva prema lijevo, bez znaka. To se može praktično
iskoristiti u kreiranju boja. Pogledajmo opet primjer umjereno sive boje:
255 |
127 |
127 |
127 |
Ovdje je transparentnost (alpha channel) 255 (11111111), dakle potpuno neprozirno, dok su kanali za red, green, blue postavljeni na 127 (01111111). To znači da je boja predstavljena cijelim brojem 11111111011111110111111101111111 odnosno -8,421,505. Naravno, cjelobrojna vrijednost nas ovdje ne zanima, bitna je binarna reprezentacija.
Dakle,
kako se kreiraju ovakve boje?. Jednostavno inicijalizirajte cijele brojeve na
vrijednosti koje želite za svaki od četiri kanala, uporabite operator
<<
kojim
ćete iz odvući na pravo mjesto i kombinirajte bitovskim OR operatorom,
|
.
Taj operator postavlja određeni bit u rezultatu na 1 ako je on tako postavljen u
bilo kojem operandu. Na primjer, da bismo kreirali čistu plavu boju,
stavimo:
int alpha = 255
<< 24
;
int red = 0
<< 16
;
int blue = 255
<< 8
;
int green = 0;
int pureblue = alpha | red | green | blue;
Možete to zapisivati i kraće, u jednom retku, npr:
int pureblue = (255 << 24) | (0 << 16) | (255 << 8) | 0; //cista plava
int halfgrey = (255 << 24) | (127 << 16) | (127 << 8) | 127; //umjereno siva
Kad znamo da su slike zapravo mreže integera, ne bi trebalo biti teško kreirati ih. Naravno, to se odnosi na one slike koje se mogu kreirati algoritamski.
Ima
više načina za kreiranje slike, tj. objekta tipa Image
iz
sirovih byteova. Najjednostavnije je uporabiti klasu java.awt.image.MemoryImageSource
.
Ona implementira sučelje java.awt.image.ImageProducer
kao i sve klase koje kreiraju slike. Njeni konstruktori su:
public MemoryImageSource(int width, int height, int[] pixels, int offset, int scan)
public MemoryImageSource(int width, int height, ColorModel cm, byte[] pixels,
int offset, int scan)
public MemoryImageSource(int width, int height, ColorModel cm, byte[] pixels,
int offset, int scan, Hashtable props)
public MemoryImageSource(int width, int height, ColorModel cm, int[] pixels,
int offset, int scan)
public MemoryImageSource(int width, int height, ColorModel cm, int[] pixels,
int offset, int scan, Hashtable properties)
Za
sada se koncentrirajmo na prvi od tih konstruktora: Ovdje je width
širina
slike u pixelima, height
je
njezina visina, a pixels
je
cjelobrojno polje koje sadrži stvarne podatke slike. Svaki broj u tom polju je
32-bitna veličina koja sadrži RGB-transparency vrijednost za jedan pojedinačni
pixel. Nadalje, offset
je
index u tom polju od kojega počinju podaci za tu sliku, a scan
je broj
pixela u svakom retku polja. Uglavnom će taj broj biti jednak vrijednosti
atributa width
.
Da
biste kreirali sliku, prvo ćete napuniti polje podacima same slike, a zatim
pomoću tog polja konstruirati novi objekt tipa java.awt.image.MemoryImageSource
.
Zatim ćete taj MemoryImageSource
predati metodi createImage()
iz klase java.awt.Component
koja će proizvesti pravi Image
objekt.
Pretpostavimo da želimo napraviti sliku široku 100 pixela i visoku 50 pixela, koja će se sastojati od čiste ljubičaste površine. Vrlo lijepa ljubičasta boja dobije se sa. 217 red, 10 green, 186 blue.
Cjelobrojnu vrijednost ove boje formirat ćemo ovako:
int red = 217;
int green = 10;
int blue = 186;
int opaque = 255;
int purple = (opaque << 24 ) | (red << 16 ) | (green << 8 ) | blue;
Slika koju želimo je 100 pixela široka i 50 pixela visoka, pa će nam za nju biti potrebno polje sa 100 * 50 = 5000 elemenata, dakle
int[] pixels = new int[5000];
Sada
možete polje napuniti ljubičastim pixelima, npr. pomoću ovakve for
petlje:
for (int i=0; i < pixels.length; i++) pixels[i] = purple;
Sad
imamo polje i možemo kreirati
MemoryImageSource
.
MemoryImageSource purpleMIS = new MemoryImageSource(100, 50, pixels, 0, 50));
Pod
pretpostavkom da smo u appletu ili nekoj drugoj podklasi od java.awt.Component
,
učinit ćemo sljedeće:.
Image purplebox = createImage(purpleMIS);
(Ako
smo negdje drugdje, trebat ćemo pozivu createImage()
dodati prefix, odgovarajuću referentnu varijablu.) Sada možemo sliku nacrtati na
uobičajen način, kao da smo je učitali s mreže.
Jedan
ImageProducer
možete koristiti za kreiranje više slika, a jedno polje pixela za kreiranje više
objekata tipa MemoryImageSource
.
Međutim, ako to radite, polje ne biste smjeli mijenjati nakon što je inicijalno
kreirano.
getRGB()
Manipulaciju
bitovima ne morate uvijek obavljati sami. Umjesto toga možete kreirati novi
objekt tipa java.awt.Color
i uporabiti njegovu metodu getRGB()
da
dobijete odgovarajuću int
vrijednost. Na primjer,
Color purple = new Color(217, 10, 186)
int p = purple.getRGB();
int[] pixels = new int[5000];
for (int i=0; i < pixels.length; i++) pixels[i] = p;
MemoryImageSource purpleMIS = new MemoryImageSource(100, 50, pixels, 0, 50);
theImage = createImage(purpleMIS);
Slika koja donosi jednobojnu podlogu kao što je prethodna, može se kreirati i na više drugih i efikasnijih načina nego što je manipuliranje pixelima. Međutim, neke je slike ipak najjednostavnije napraviti baš takvim, algoritamskim pristupom. Pogledajmo sljedeći applet koji kreira sliku veličine 256 x 256 pixela na kojoj se pretapaju crvena, zelena, crna i žuta boja.
(Kvaliteta ove slike ovisi u mnogome i o kvaliteti monitora.)
import java.applet.*;
import java.awt.*;
import java.awt.image.*; // Don't forget this!
public class RGBlend extends Applet {
private Image picture;
public void init() {
int opaque = 255 << 24;
int[] pixels = new int[256*256];
for (int i=0; i < 256; i++) {
int red = i << 16;
for (int j = 0; j < 256; j++) {
int green = j << 8;
pixels[i*256 + j] = opaque | red | green;
}
}
MemoryImageSource RGBlendMIS =
new MemoryImageSource(256, 256, pixels, 0, 256);
this.picture = this.createImage(RGBlendMIS);
}
public void paint(Graphics g) {
// picture is created internally so we know it won't be null
g.drawImage(this.picture, 0, 0, this);
}
}
<APPLET
CODE="RGBlend.class"
CODEBASE="http://student.math.hr/~vedris/java/classes/ImageProcessing"
WIDTH=256
HEIGHT=256>
</APPLET>
Java podržava filtriranje slika, skup postupaka kojim se slika transformaira na neki predvidljiv način. Na primjer, filtar može ukloniti zelenu ili plavu komponentu slike, ostavljajući samo crvenu. Ili može izoštriti, odnosno zamutiti linije slike. Izučavanje filtara još je otvoreno područje. Ovdje ćemo demonstrirati nekoliko jednostavnih filtara. Kompliciraniji se rade na isti način, samo što koriste kompliciranije algoritme za filtriranje podataka.
U
Javi nam je, da bismo radili s filtrima, potrebna podklasa od java.awt.image.ImageFilter
i podklasa od java.awt.image.FilteredImageSource
.
Ova druga implementira sučelje java.awt.image.ImageProducer
.
Počinje raditi sa postojećom slikom, ali je provlači kroz odgovarajući
ImageFilter
prije nego pošalje pixele nekom ImageObserver
u
ili ImageConsumer
u.
Klasa
java.awt.image.RGBImageFilter
je apstraktna podklasa od java.awt.image.ImageFilter
.
Omogućuje pisanje filtara koji modificiraju pixele, jedan po jedan. Koristi se
kad je filtriranje svakog pixela nezavisno od ostalih pixela. Nije pogodna za
filter u kojima filtriranje ovisi o susjednim pixelima kao što je npr. filtar
koji uprosjećuje okolne pixele.
Jedina
metoda iz te klase koju trebate prekriti je filterRGB()
public abstract int filterRGB(int x, int y, int rgb)
Zbog
performansi dobro je prekriti i metodu filterRGBPixels()
i postaviti atribut canFilterIndexColorModel
na true
. Taj
atribut određuje da li filtar ovisi ili ne ovisi o poziciji pixela. Ako je
true
, onda se
umjesto filtriranja svakog pixela slika filtrira samo ograničen broj stavaka u
mapi boja, što je mnogo brže. Po pretpostavci filtar ovisi o poziciji pa je taj
atribut inicijalno false
.
public void filterRGBPixels(int x, int y, int w, int h,
int pixels[], int offset, int scan)
Metoda
filterRGBPixels()
prosljeđuje svaki pixel iz polja pixela metodi filterRGB()
jedan po jedan. Međutim, ponekad možete poboljšati performanse izbjegavanjem
nepotrebnih poziva metoda i filtriranja pixela jedan po jedan, posebno ako je
canFilterIndexColorModel
postavljen na false
.
Evo jednog jednostavnog filtra koji propušta samo plave komponente slike.
import java.awt.image.*;
public class BlueFilter
extends RGBImageFilter
{
protected boolean canFilterIndexColorModel = true;
public int filterRGB(int x, int y, int rgb) {
return rgb & 0xFF0000FF;
}
}
Atribut
canFilterIndexColorModel
je postavljen na true
jer je
filtriranje neovisno o poziciji. Bitovski operator, &
, koristi
se za selektiranje samo prvih osam i zadnjih osam bitova vrijednosti broja
rgb
. Stupanj
transparentnosti je spremljen u prvih 8 bitova. Plava komponenta se nalazi u
zadnjih 8 bitova. FF je 11111111 pa su svi bitovi plave boje i prozirnosti
zadržani. Ostali će nestati.
Da
bismo koristili taj plavi filtar, kreirat ćemo objekt tipa java.awt.image.FilteredImageSource
.
Na primjer,
Image src = getImage(getDocumentBase(), filename);
picture = createImage(new FilteredImageSource(src.getSource(), new BlueFilter()));
Metoda
getSource()
vraća referencu na objekt tipa ImageProducer
koji je proizveo sliku (objekt tipa Image
).
Evo sada appleta koji učitava sliku navedenu u oznaci <PARAM> i zatim na nju primjenjuje plavi filtar.
import java.awt.*;
import java.awt.image.*;
import java.applet.*;
public class BlueImage extends Applet {
private Image picture;
public void init() {
String filename = this.getParameter("imagefile");
if (filename != null) {
Image src = this.getImage(getCodeBase(), filename);
this.picture = this.createImage(
new FilteredImageSource(src.getSource(), new BlueFilter()));
}
}
public void paint (Graphics g) {
if (this.picture != null) {
g.drawImage(this.picture, 0, 0, this);
}
else {
g.drawString("Nema slike", 20, 20);
}
}
}
<APPLET
CODE="BlueImage.class"
CODEBASE="http://student.math.hr/~vedris/java/classes/ImageProcessing"
WIDTH=435
HEIGHT=300>
<PARAM
NAME="imagefile" VALUE="sun.jpg">
</APPLET>
Sljedeći filtar prevodi boje slike u skalu sivih tonova. Crvena, zelena i plava boja su ujednačene. Rezultirajuća boja je siva sa istim prosječnim intenzitetom.
import java.awt.image.*;
public class GreyFilter extends RGBImageFilter {
protected boolean canFilterIndexColorModel = true;
public int filterRGB(int x, int y, int rgb) {
int red = rgb & 0x00FF0000;
red >>>= 16;
int green = rgb & 0x0000FF00;
green >>>= 8;
int blue = rgb & 0x0000FF;
int grey = (red + green + blue)/3;
return (0x000000FF << 24) | (grey << 16) | (grey << 8) | grey;
}
}
Primijetite
da su prije računanja prosjeka crvena i zelena komponenta pomaknute desno za 16,
odnosno 8 bitova respektivno. To ih baca u raspon od 0 do 255 i omogućuje da sa
svakom od njih radimo pojedinačno. Operator >>>
pomiče bitove udesno bez predznaka.
import java.awt.*;
import java.awt.image.*;
import java.applet.*;
public class GreyImage extends Applet {
private Image picture;
public void init() {
String filename = this.getParameter("imagefile");
if (filename != null) {
Image source = this.getImage(getCodeBase(), filename);
this.picture = this.createImage(
new FilteredImageSource(source.getSource(), new GreyFilter()));
}
}
public void paint (Graphics g) {
if (this.picture != null) {
g.drawImage(this.picture, 0, 0, this);
}
else {
g.drawString("Nema slike", 20, 20);
}
}
}
<APPLET
CODE="GreyImage.class"
CODEBASE="http://student.math.hr/~vedris/java/classes/ImageProcessing"
WIDTH=435
HEIGHT=300>
<PARAM
NAME="imagefile" VALUE="sun.jpg">
</APPLET>
Mogu se pisati filtri koji ovise o položaju pixela. Na primjer, sljedeći filtar zatamnjuje sliku tako da je zatamnjenje to veće što se više udaljujemo od gornjeg lijevog ugla.
import java.awt.image.*;
public class ShadowFilter extends RGBImageFilter {
private double edge;
public ShadowFilter(int width, int height) {
edge = Math.sqrt(width*width + height*height);
}
public int filterRGB(int x, int y, int rgb) {
double fraction = 1.0 - Math.sqrt(x*x + y*y)/edge;
if (fraction <= 0) return 0xFF000000;
int red = rgb & 0x00FF0000;
red >>>= 16;
int green = rgb & 0x0000FF00;
green >>>= 8;
int blue = rgb & 0x0000FF;
int r = (int) (red * fraction);
int g = (int) (green * fraction);
int b = (int) (blue * fraction);
return (0x000000FF << 24) | (r << 16) | (g << 8) | b;
}
}
import java.awt.*;
import java.awt.image.*;
import java.applet.*;
public class ShadowImage extends Applet {
private Image picture;
public void init() {
String filename = this.getParameter("imagefile");
Image src = this.getImage(getCodeBase(), filename);
this.picture = this.createImage(new FilteredImageSource(src.getSource(),
new ShadowFilter(this.getSize().width, this.getSize().height)));
}
public void paint (Graphics g) {
g.drawImage(this.picture, 0, 0, this);
}
}
Primijetite
da ovdje canFilterIndexColorModel
više nije postavljen na true
. Svaki
pixel mora se tretirati individualno. Također primijetite da ovaj filtar ima
konstruktor. Iako nije nužan, pokazuje se korisnim.
<APPLET
CODE="ShadowImage.class"
CODEBASE="http://student.math.hr/~vedris/java/classes/ImageProcessing"
WIDTH=435
HEIGHT=300>
<PARAM
NAME="imagefile" VALUE="sun.jpg">
</APPLET>
Do sad smo pretpostavljali da se svaki pixel može filtrirati neovisno o susjednim pixelima. To nije uvijek tako. Na primjer, filtri za izoštravanje, zamagljivanje i slično, traže značajnu količinu podataka o drugim dijelovima slike.
Kad
filtar mora uzimati u obzir vrijednosti ne samo filtriranih pixela nego i
drugih, nije više moguće koristiti jednostavnu klasu java.awt.image.RGBImageFilter.
Umjesto toga treba raditi direktno sa java.awt.image.ImageFilter
.
Da biste implementirali svoj filtar, potrebno je prekriti dvije metode
setPixels()
.
public void setPixels(int x, int y, int w, int h, ColorModel model,
byte pixels[], int offset, int scan)
public void setPixels(int x, int y, int w, int h, ColorModel model,
int pixels[], int offset, int scan)
Java omogućuje izvođenje audio datoteka kodiranih u određenim formatima. To mogu biti AIFF, AU, WAV, MIDI, and RMF datoteke.
Klasa
java.applet.Applet
sadrži dvije metode pomoću kojih možete skinuti zvučnu datoteku sa nekog URL-a i
izvesti je.
public void play(URL soundfile)
public void play(URL directory, String filename)
Uobičajeno je da se te adrese zadaju u odnosu na codeBase ili documentBase, ili URL može biti zadan pomoću oznake <PARAM>.
Audio primjer za sljedeće applete možete skinete sa adrese http://student.math.hr/~vedris/java/sounds/spacemusic.au).
import java.applet.*;
public class SoundApplet extends Applet {
public void init() {
String soundfile = this.getParameter("soundfile");
if (soundfile != null) this.play(this.getCodeBase(), soundfile);
}
}
<APPLET
CODE="SoundApplet.class"
CODEBASE="http://student.math.hr/~vedris/java/classes/SoundProcessing"
WIDTH=200
HEIGHT=100>
<PARAM
NAME="soundfile" VALUE="spacemusic.au">
</APPLET>
Umjesto
pojedinačne izvedbe od početka do kraja, applet može izvoditi zvučni primjer
kontinuirano, tako da ga učita u objekt "
tipa"
java.applet.AudioClip
(primijetite da je to sučelje, ne klasa!) i nakon toga izvvodi pomoću metode
loop()
.
Prvo treba snimiti zvuk u AudioClip
na
primjer ovako:
AudioClip ac = this.getAudioClip(new URL(
"
http://student.math.hr/~vedris/java/sounds/spacemusic.au"));
Tada,
kad imate objekt koji je AudioClip
,
pozovete njegovu metodu loop()
:
ac.loop();
Kad
želite zaustaviti izvedbu, pozvat ćete metodu stop()
:
ac.stop();
Evo appleta koji omogućuje kontinuiranu izvedbu zvučnog primjera:
import java.applet.*; // java.applet.Applet isn't enough
public class SoundLoopApplet extends Applet {
AudioClip theSound;
public void init() {
String soundfile = this.getParameter("soundfile");
if (soundfile != null) {
theSound = this.getAudioClip(this.getCodeBase(), soundfile);
}
}
public void start() {
if (theSound != null) theSound.loop();
}
public void stop() {
if (theSound != null) theSound.stop();
}
}
<APPLET
CODE="SoundLoopApplet.class"
CODEBASE="http://student.math.hr/~vedris/java/classes/SoundProcessing"
WIDTH=200
HEIGHT=100>
<PARAM
NAME="soundfile" VALUE="spacemusic.au">
</APPLET>
Primijetite
da sam applet vodi računa o tome da izvedba prestane kad korisnik napusti
stranicu pa se pozove metoda stop()
. U
protivnom bi se izvedba nastavila beskonačno, sve dok korisnik ne ugasi browser.