Predavanje br. index|1|2|3|4|5|6|7|8|9|10|11|12|13|14|HOME


Deveto predavanje – izbornici, slike i zvukovi

Š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


Što je izbornik?

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.


Klase izbornika

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.


Kreiranje izbornika

Izbornike je poželjno potpuno izgraditi prije nego ih prikažete. Tipični redosljed je ovakav:

  1. kreirajte novi objekt tipa MenuBar.
  2. kreirajte novi objekt tipa Menu.
  3. dodajte opcije objektu tipa Menu.
  4. ako je potrebno, ponovite korake 2 i 3.
  5. dodajte objekt tipa 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, MenuItemare 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 MenuBarovu 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);

Primjer izbornika

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>


Događaji vezani uz izbornike

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

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();

Padajući izbornici (Popup Menus)

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 MenuBaru. 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

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.


Kamo staviti slike?

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.


Učitavanje slika

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.


Crtanje slika

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.


Uporaba povratne vrijednosti metode 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>


Primjer crtanja slika

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>


Promjena veličine slike

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>


Ustanovljavanje veličine slike

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>


Paket 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:

Sučelja

Klase


Sučelja ImageProducer, ImageObserver, ImageConsumer

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 ImageObservera. 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 ImageObservera da je pristiglo još podataka o slici pa se njen prikaz može osviježiti.


Sučelje ImageConsumer

Sučelje java.awt.image.ImageConsumer je manje obično. Dok ImageProducer nekom ImageObserveru samo kaže da je dio slike spreman, dotle zainteresiranom ImageConsumeru 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)

Čekanje na učitavanje slike

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.


Prekrivanje metode 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>


Što je zapravo slika?

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.

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

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 <<

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

Kreiranje slika

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.


Primjer kreiranja slika

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.


Metoda 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);

Pretapanje boja

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>


Filtriranje slika

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 ImageObserveru ili ImageConsumeru.


Klasa RGBImageFilter

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.


Primjer plavog filtra

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>


Primjer filtra sivih tonova

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>


Filtri koji ovise o položaju

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>


Filtri koji ovise o adjungiranim pixelima

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) 

Audio

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>


Kontinuirana izvedba

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.