Klasa Graphics |
Digresija: JBuilder na CD-u sadrzi 3--dnevnu probnu instalacionu verziju JBuilder EnterpriseEdition
za Windows, Linux, Solaris. Ta verzija ce preci u besplatan PersonalEdition alat nakon 30 dana.
Dobijanje licencnog kljuca pre upotrebe alata JBuilder-a je preko Web strane
http://www.borland.com/jbuilder/keys/jb6_ent_steps.html
Crtanje se u Javi obavlja pomocu objekata klase java.awt.Graphics.
Graficki objekt se daje kao argument metodi paint(Graphics g) koju
klasa java.applet.Applet nasledjuje od klase java.awt.Container.
Sve sto bude receno o crtanju u apletima vazi i za objekte kao sto
su paneli, okviri, dugmici, pozadine itd.
Iscrtavanje se uglavnom obavlja u metodu paint(). Iscrtavanje
se može izvoditi direktno na apletu ili na radnoj površini koje će zbog
svojih specifičnosti biti obrađeno kasnije.
Svaki objekt tipa Graphics ima svoj vlastiti koordinatni sistem i metode
za crtanje stringova, linija, pravougaonika, krugova, poligona i tako dalje.
Crtanje u Javi počinje od pojedinačnog objekta tipa Graphics. Pristup tom
objektu ostvaruje se metodom paint(Graphics g) u apletu..
Primer poziva metode za crtanje:
g.drawString("Hello World", 0, 50)
--------------------------------------------------------------------------------
Iscrtavanje linija
Za crtanje prave linije poziva se metod drawline() cija sintaksa je:
public abstract void drawLine(int x1,
int y1,
int x2,
int y2)
Poziva se ovako:
g.drawLine(x1, y1, x2, y2)
Pri tome su (x1, y1) i (x2, y2) krajnje tacke linije, a g je objekt
tipa Graphics pomocu kog se iscrtava linija.
Primer koji iscrtava liniju dijagonalno preko appleta.
import java.applet.*;
import java.awt.*;
public class Dijagonala extends Applet {
public void paint(Graphics g) {
g.drawLine(0, 0, this.getSize().width, this.getSize().height);
}
}
<APPLET code="Dijagonala.class"
HEIGHT="200" WIDTH="200">
</APPLET>
Klasa Graphics sadrži nekoliko metoda za iscrtavanje i sve one imaju
ograničenja poput:
debljina linije je debljina tačke
objekti se iscrtavaju u tekućoj boji
No, metodi su sasvim dovoljni za dijagrame, isticanje teksta, jednostavne
animacije,...
Primer koji iscrtava na apletu tanku liniju od pozicije koordinatnog početka do pozicije koja je od nje udaljena 100 tačaka desno i 50 tačaka nadole. Takođe u primeru se vrši i scrtavanje deblje linije, tako što se uz osnovnu liniju iscrta još nekoliko linija.
import java.awt.*;
import java.applet.*;
public class TankaDebelaLinija extends Applet {
public void paint(Graphics g) {
g.drawLine(0, 0, 100, 50); /* iscrtava osnovnu liniju od (0,0) do (100, 50) */
g.setColor(new Color(255,0,0)); /* metod obradjen u 5.
nastavku-metod koji podesava tekucu
boju objekta pre njegovog iscrtavanja; zadaje se kao triplet intenziteta
boja u RGB modelu */
g.drawLine (50,75,200,25);
g.drawLine (50,75,200,26); /* druga naredba se koristi
da pojaca ispis iz prethodne naredbe*/
g.setColor(new Color(0,255,0)); /* zelena*/
for (int y1=120; y1<130; y1++)
g.drawLine(100, y1, 200, y1+20); /*
uz osnovnu linju iscrtavanje se pojacava sa dodatnih 9 linija*/
}
}
Primer koji kreira animaciju u formi linije koja rotira oko centra (120,120)
i iscrtava krug.
Matematički model zahteva da se uoči da pri ma kom uglu, poluprečnik
se izdvaja kao hipotenuza
trougla čije katete se prostiru od centra kruga do x, y koordinata
neke tačke na kružnici.
x= (int) (java.lang.Math.cos(ugao)*100) + 120; /* 100=duzina linije,
poluprecnika;
(120, 120) koordinate centra*/
import java.awt.*;
import java.applet.*;
public class TragRotacije extends Applet {
Color bela=new
Color(180,255,255); /* nije bas (255,255,255) ali ostavlja trag*/
Color crna=new
Color(0,0,0);
public void
paint(Graphics g) {
int x,y; /*tacke granice kruga*/
double
ugao=0;
while(ugao
< 6.28) /* Java meri uglove u radijanima, 2PI radijana za
360 stepeni;
while(ugao < 2*Math.PI) */ {
x= (int) (java.lang.Math.cos(ugao)*100) + 120;
y= (int) (java.lang.Math.sin(ugao)*100) + 120;
g.setColor(crna);
g.drawLine(120,120,x,y); /* iscrtava polaznu liniju */
/*prazna petlja za usporeni prikaz*/
for(int pauza=0; pauza <20000; pauza ++) ;
g.setColor(bela);
g.drawLine(120,120,x,y); /* novi polozaj*/
ugao=ugao+0.01;
}
g.setColor(crna);
g.drawLine(120,120,220,120); /* ponovo se iscrtava da prikaze krajnji polozaj*/
}
}
--------------------------------------------------------------------------------
Crtanje pravougaonika
Pravougaonik se iscrtava pomocu objekta g iz klase Graphics i metode drawRect() cija je sintaksa:
public void drawRect(int x,
int y,
int width,
int height)
Poziva se ovako:
public void drawRect(x, y, width, height)
Prva dva argumenta su koordinate gornjeg levog ugla pravougaonika, dok su ostala dva njegova sirina i visina.
Primer koji iscrtava pravougaonik oko appleta.
import java.applet.*;
import java.awt.*;
public class Pravougaonik extends Applet {
public void paint(Graphics g) {
g.drawRect(0, 0, this.getSize().width - 1, this.getSize().height - 1);
}
}
Znamo da getSize().width je sirina pravougaonika, a getSize().height
njegova visina.
Zasto se onda pravougaonik iscrtava samo do getSize().height-1 i getSize().width-1?
Zato jer se levi gornji ugao nalazi u tacki (0, 0), a ne u (1, 1). To znaci da aplet velicine 100 x 200 piksela ukljucuje tacke s x-koordinatama izmedju 0 i 99, a ne izmedju 0 i 100. Slicno, y-koordinate su izmedju 0 i 199 ukljucivo, a ne izmedju 0 i 200.
Za crtanje kvadrata ne postoji posebna drawSquare() metoda. Kvadrat
je pravougaonik jednakih stranica.
--------------------------------------------------------------------------------
Iscrtavanje ispunjenog pravougaonika
Metoda drawRect() crta prazan pravougaonik. Ako se zeli crtati kao
ispunjen, postoji metod
fillRect() cija je sintaksa:
public abstract void fillRect(int
x,
int y,
int width,
int height)
Primer koji crta ispunjeni pravougaonik u centru apleta. Mora se razlikovati velicina pravougaonika od velicine appleta.
import java.applet.*;
import java.awt.*;
public class PopuniCentriraj extends Applet {
public void paint(Graphics g) {
int appletVisina = this.getSize().height;
int appletSirina = this.getSize().width;
int rectVisina = appletVisina/3;
int rectSirina = appletSirina/3;
int rectTop = (appletVisina
- rectVisina)/2;
int rectLeft = (appletSirina
- rectSirina)/2;
g.fillRect(rectLeft, rectTop, rectSirina-1, rectVisina-1);
}
}
<APPLET code="PopuniCentriraj.class"
HEIGHT="50" WIDTH="40">
</APPLET>
Primer koji iscrtava pravougaonik tanjih i ispod njega pravougaonik
debljih ivica. (Metod drawRect iscrtava tanke linije kao stranice).
Unutar pravougaonika ispisati stringove Prvi, Drugi pojacanim fontom
velicine 14pt tipa SansSerif.
Ako se zele deblje linije za ivice, onda se moze upotrebiti petlja i iscrtati jedan ispunjeni pravougaonik unutar drugog.
import java.applet.*;
import java.awt.*;
public class Pravougaonik2 extends Applet {
Color crvena=new Color(0,255,255);
Color zuta=new Color(255,255,0);
Color crna=new Color(0,0,0);
Font niska=new Font("SansSerif", Font.BOLD, 14);
public void paint(Graphics g) {
g.setFont(niska); /* postavlja se opis fonta
za tekuci objekat */
g.setColor (crvena); /* tekuca boja objekta
*/
/* iscrtava se 5 uzastopnih pravougaonika;
pocev od pravougaonika (50,50, 150, 75);
uzastopni pravougaonici
su 2 piksel manji, a pocinju 1 piksel unutra i nadole, te se i od sirine
i od duzine oduzima 2*i */
for (int i=0; i<5; i++)
g.drawRect(50+i,
50+i, 150-2*i, 75-2*i);
g.setColor(crna); /* postavlja se boja ispisa
niske Prvi u 1. pravougaoniku */
g.drawString("Prvi",80,90);
g.setColor(crvena); /* postavlja se boja ispisa
pravougaonika 2 koji se nalazi ispod pravougaonika 1*/
g.fillRect(50, 150,200,100);
g.setColor(zuta); /* menja se unutrasnja
boja, tj. ako je unutrasnja boja ista kao i pozadina, onda se barem vidi
okvir pravougaonika*/
g.fillRect(60, 160,180,80);
g.setColor(crna); /* postavlja se boja ispisa
niske Drugi u 2. pravougaoniku */
g.drawString("Drugi",100,200);
}
}
--------------------------------------------------------------------------------
Nacrtani pravougaonik moze se izbrisati metodom clearRect() cija je
sintaksa:
public abstract void clearRect(int x,
int y,
int width,
int height)
Primer koji koristi metod clearRect() da bi prikazao bljesak pravougaonika na ekranu.
import java.applet.*;
import java.awt.*;
public class Blink extends Applet {
public void paint(Graphics g) {
int appletH = this.getSize().height;
int appletW = this.getSize().width;
int rectH = appletH/3;
int rectW = appletW/3;
int rectTop = (appletH
- rectH)/2;
int rectLeft = (appletW
- rectW)/2;
for (int i=0; i < 1000000; i++) {
g.fillRect(rectLeft, rectTop, rectW-1,
rectH-1);
g.clearRect(rectLeft, rectTop, rectW-1,
rectH-1);
}
}
}
Ovo nije nacin kako se u praksi radi animacija, no to je privremeno
resenje dok se ne nauci Java mehanizam rada sa nitima (thread).
--------------------------------------------------------------------------------
Elipse i kruznice
Elipse i kruznice crtaju se pomocu metode drawOval(), a pune pomocu
metode fillOval() cije su sintaksne signature:
public abstract void drawOval(int x,
int y,
int width,
int height)
public abstract void fillOval(int x,
int y,
int width,
int height)
Argumenti ovih metoda predstavljaju koordinate gornjeg levog ugla, sirinu i visinu pravougaonika kom je elipsa upisana.
Nema posebne metode za crtanje kruznice. Kruznicu smatrati je elipsom
upisanom u kvadrat.
Primer apleta koji iscrtava elipsu i krug zajedno sa opisanim pravougaonicima oko njih.
import java.applet.*;
import java.awt.*;
public class ElipsaKrugPravougaonik extends Applet {
Color siva= new Color(160,160,160);
Color crna= new Color(0,0,0);
public void paint(Graphics g) {
g.drawRect(10,10,150,100); /* pravougaonik
1*/
g.setColor(siva);
g.fillOval(10,10,150,100); /* ispunjena siva
elipsa u pravougaoniku 1; stvarni parametri identicni
kao u pozivu metoda drawRect
*/
g.fillRect(180,40, 100, 100); /* sivi kvadrat
*/
g.setColor(crna);
g.fillOval(180,40,100,100); /*crni krug u sivom kvadratu*/
g.setColor(siva);
g.fillOval(200,60,60,60); /* sivi krug u crnom krugu
*/
}
}
Java sadrzi metode za crtanje praznih i ispunjenih lukova. Oni su izvedeni
iz metoda za crtanje elipsi, ali imaju dva dodatna parametra - pocetak
luka i velicinu ugla luka. To su metode drawArc() i fillArc(). Ponasaju
se slicno kao drawOval() i fillOval().
Signature:
public abstract void drawArc(int x,
int y,
int width,
int height,
int startAngle,
int arcAngle)
public abstract void fillArc(int x,
int y,
int width,
int height,
int startAngle,
int arcAngle)
U pravougaonik se upisuje najveci moguci luk. Lokacija luka od 0 stepeni,
kao i smer, tj. odgovor da li je luk nacrtan u smeru kazaljke na satu ili
suprotnom ne zavisi od platforme.
Na primer, poziv
g.fillArc(10,10,100,100,0,90)
iscrtava isecak kruga (width=height=100) ciji precnik je 100 tacaka
i gornji levi ugao opisanog
kvadrata je na poziciji 10,10. Isecak ima formu prve cetvrtine kruga.
Uglovi luka se zadaju u celobrojnim vrednostima stepena, a ne u radijanima
(koji su argumenti trigonomterijskih funkcija). 0 stepeni bi bilo na vrednosti
3 casovnika,...i uglovi se mere suprotno kretanju kazaljki na satu. Ako
se zeli zadavanje uglova u smeru kretanaj kazaljke na satau, onda se koriste
negativne vrednosti uglova.
Napisati aplet koji iscrtava sledecu sliku:
import java.applet.*;
import java.awt.*;
public class Lukovi extends Applet {
public void paint(Graphics g) {
g.fillArc(10,10,100,100,
0, 90); /* ispunjena prva cetvrtina kruga */
g.drawArc(10,10,100,100,90,180);
/* u istom krugu, bez granice druge cetvrtine*/
g.fillArc(10,120,100,100,
90, -60); /*pocetak na vrh i ispod se crta drugi luk, ispunjen kruzni isecak
na 60 stepeni udesno */
g.fillArc(120,120,100,50, 270,-210);
/*fragment neispunjene elipse; isto kao
g.fillArc(120,120,100,50,
60, 210);*/
}
}
--------------------------------------------------------------------------------
Primer apleta koji crta niz ispunjenih, koncentricnih krugova, naizmenicno crvenih i zelenih.
import java.applet.*;
import java.awt.*;
public class Bullseye extends Applet {
public void paint(Graphics g) {
int rectLeft, rectTop, rectHeight, rectWidth;
int appletHeight = this.getSize().height;
int appletWidth = this.getSize().width;
for (int i=8; i >= 0; i--) {
if ((i % 2) == 0) g.setColor(Color.red);
else g.setColor(Color.green);
// Centriranje pravougaonika
rectHeight = appletHeight*i/8;
rectWidth = appletWidth*i/8;
rectLeft = appletWidth/2 - i*appletWidth/16;
rectTop = appletHeight/2 - i*appletHeight/16;
g.fillOval(rectLeft, rectTop, rectWidth,
rectHeight);
}
}
}
Klasa koja crta ovu sliku je velicine 681 byte. Ekvivalentna GIF slika
je velika 1,850 byte, dakle do tri puta vise.
--------------------------------------------------------------------------------
Poligoni
U Javi su pravougaonici definisani pomocu pozicije svojeg gornjeg levog ugla, visine i sirine. Implicitno se podrazumeva da pravougaonik nije rotiran. Ako jeste, smatra se specijalnim slucajem poligona, tj. objekta iz klase java.awt.Polygon.
Poligoni su definisani svojim temenima bez dodatnih pretpostavki osim
da leze u dvodimenzionalnoj ravnii.Osnovni konstruktor klase Polygon je
public Polygon(int[] xpoints,
int[] ypoints,
int npoints)
xpoints je niz koje sadrzi x koordinate temena poligona, a ypoints
niz koje sadrzi y koordinate njegovih temena. Oba niza imajui duzinu npoints.
Primer konstrukcije pravouglog trougla:
int[] xpoints = {0, 3, 0};
int[] ypoints = {0, 0, 4};
Polygon pTrougao = new Polygon(xpoints, ypoints, 3);
Da bi obaj trougao bio iscrtan, unutar paint() metode se poziva iz klase java.awt.Graphics metod drawPoligon() :
g.drawPolygon(myTriangle);
Dakle, sintaksa metoda je public void drawPolygon(Polygon p)
Postoji i druga verzija metode drawPolygon() koja ima signaturu:
public abstract void drawPolygon(int[] xPoints,
int[] yPoints,
int nPoints)
a poziva se kao:
g.drawPolygon(xpoints, ypoints, xpoints.length);
Postoji i polimorfna metoda fillPolygon().
Sintaksa metoda:
g.fillPolygon(myTriangle);
g.fillPolygon(xpoints, ypoints, xpoints.length());
--------------------------------------------------------------------------------
Visestruke linije (polylines)
Java automatski zatvara poligone koje nacrta.
Ako zelite iscrtati otvorene poligone, koristi se metod drawPolyline().
Sintaksa:
public abstract void drawPolyline(int[] xPoints,
int[] yPoints,
int nPoints)
Zadaci za vežbanje
1. Napisati metod public void debljaLinija (int x, int y, int x1, int y1, int w, Graphics g) koji u ciklusu iscrtava deblje linije do w puta od osnovnih. Napisati aplet koji testira upotrebu ovog metoda.
2. Napisati metod public void bojaLinija (int x, int y, int x1, int
y1, Color c, Graphics g) koji
iscrtava liniju u zadatoj boji. Podesavanje boje se odnosi samo
na liniju koja se iscrtava, a po izlasku iz metoda, tekuca boja treba da
ostane kao i pre ulaska u potprogram.
Napisati aplet koji testira upotrebu ovog metoda.
Napomena: dozvoljeno je koristiti metod g.GetColor() koji
vraca vrednost tekuce boje.
3. Napisati aplet koji ce omoguciti da korismik slobodno izcrtava
linije.
Napomena: dozvoljeno je koristiti metode fillRect, fillOval za iscrtavanje
tacaka, kao i dodatno dugme koje ce brisati ekran (upotrebiti metod za
uklanjanje pravougaonika clearRect).
Kružni dijagrami (pie charts)
Napisati aplet koji iscrtava nekoliko kružnih isečaka u obliku kružnog dijagrama , gde boje i veličine lukova se zadaju u programu.
import java.awt.*;
import java.applet.*;
public class KruzniDijagram extends Applet
{
double [] vred=new double [6]; /*udeo vrednosti
u dijagramu*/
int [] kriske=new int [6]; /* stepen luka svake
kriske*/
Color [] boje=new Color[6]; /*boje svake kriske */
public void init()
{ double ukupno=0;
/* zadaju se neke vrednosti, ciji odnos
mora prikazati kruzni dijagram */
vred[0]=1000; vred[1]=600;
vred[2]=650; vred[3]=1300; vred[4]=400;
vred[5]=1450;
/* svaki element niza se prikazuje u velicini lukova od 0
do 360 => formiranje vrednosti lukova */
for (int i=0; i<6; i++) ukupno+=vred[i];
for (int i=0; i<6; i++) kriske[i]=(int) (vred[i]/ukupno*360);
/* zadavanje boje kriski */
boje[0]=Color.red; boje[1]=Color.green;
boje[2]=Color.blue; boje[3]=Color.gray;
boje[4]=Color.red; boje[5]=Color.yellow;
}
public void paint(Graphics g)
{
int start=0;
for (int i=0; i<6; i++)
{
g.setColor(boje[i]); /* boja tekuceg isecka */
g.fillArc(20,20,200,200,start, kriske[i]); /* na start se doda kriske[i]
i dobija se
pocetni ugao za sledeci isecak */
start+=kriske[i];
}
}
}
U ovom primeru umesto zadavanja boja u formi RGB tripleta,
Color medGray = new Color(127, 127, 127);
Color cream = new Color(255, 231, 187);
Color lightGreen = new Color(0, 55, 0);
upotrebljene su predefinsane boje
Color.red, Color.blue,...
Boje su u Javi instance klase java.awt.Color. Obavezno je importovati
tu klasu pre upotrebe boja..
Nekoliko najčešće korištenih boja dostupne su i po nazivu. To su:
Color.black
Color.blue
Color.cyan
Color.darkGray
Color.gray
Color.green
Color.lightGray
Color.magenta
Color.orange
Color.pink
Color.red
Color.white
Color.yellow
Boja nije svojstvo izvesnog stringa, elipse i slično, nego deo
objekta tipa Graphics koji obavlja crtanja. Za promenu boje potrebno je
promijeniti boju objekta iz Graphics. I sva tekuća iscrtavanja poprimaju
tu boju, do sledeće izmene.
Kad se aplet počne izvršavati, njegova boja je crna. Može se promeniti
stavljajući npr. g.setColor(Color.red). Može se vratit na početnu ako se
pozove g.setColor(Color.black).
Digresija:
Sistemske boje
Počev od Java 1.1, postoji klasa java.awt.SystemColor
koja je podklasa od java.awt.Color i omogućuje korištenje boja za nativne
komponente. Na primer, ako želite pozadinu apleta obojiti kao i pozadinu
prozora, onda u init() metodi se obavi podešavanje:
public void paint (Graphics g) {
g.setColor(SystemColor.control);
g.fillRect(0, 0, this.getSize().width,
this.getSize().height);
}
Raspložive su sledeće sistemske boje:
SystemColor.desktop // Background color of desktop
SystemColor.activeCaption // Background color
for captions
SystemColor.activeCaptionText // Text color for
captions
SystemColor.activeCaptionBorder // Border color
for caption text
SystemColor.inactiveCaption // Background color
for inactive captions
SystemColor.inactiveCaptionText // Text color
for inactive captions
SystemColor.inactiveCaptionBorder // Border color
for inactive captions
SystemColor.window // Background for windows
SystemColor.windowBorder // Color of window border
frame
SystemColor.windowText // Text color inside windows
SystemColor.menu // Background for menus
SystemColor.menuText // Text color for menus
SystemColor.text // background color for text
SystemColor.textText // text color for text
SystemColor.textHighlight // background color
for highlighted text
SystemColor.textHighlightText // text color for
highlighted text
SystemColor.control // Background color for controls
SystemColor.controlText // Text color for controls
SystemColor.controlLtHighlight // Light highlight
color for controls
SystemColor.controlHighlight // Highlight color
for controls
SystemColor.controlShadow // Shadow color for
controls
SystemColor.controlDkShadow // Dark shadow color
for controls
SystemColor.inactiveControlText // Text color
for inactive controls
SystemColor.scrollbar // Background color for
scrollbars
SystemColor.info // Background color for spot-help
text
SystemColor.infoText // Text color for spot-help
text
Domaći: Modifikovati program tako da boja i veličine lukova se uzimaju
kao vrednosti elementa
param unutar apleta.
Učitavanje slika
Slike koje se prikazuju pomocu Java apleta ucitavaju se s mreze preko
URL koji locira datoteku sa slikom. Mogu se nalaziti na serveru, lokalnom
disku,... ili bilokoje odrediste do ko applet ima dozvoljen pristup preko
URL. Npr. URL koji ukazuje na lokalni disk Vseg racunara ne mora biti pristupacan
nekom s mreze, tako da aplet moze da Vam i ne radi korektno na mrezi, iako
je funkcionisao na lokalnom racunaru.
Najcesce se slike stavljaju u isti direktorijum gde je i applet ili
u onaj gde je i HTML datoteka. Obicno se slika postavi u appletov direktorijum
ako se se koristiti u svim instancama apleta, a u HTML direktorijum
ako razlicite instance appleta koriste razlicite slike. Treca mogucnost
je staviti sve slike u neki posebni direktorij i onda preko <PARAM>
oznake zadati lokaciju apletu.
Ako je poznat tacan URL slike, moze se ucitati pomocu metode getImage():
URL imageURL = new URL("http://www.google.com/logo.gif");
java.awt.Image img = this.getImage(imageURL);
Ili u jednoj naredbi:
Image img = this.getImage(new URL("http://www.google.com/logo.gif"));
Metoda getImage() pripada klasi java.applet.Applet. Za URL objekte koristi se klasu java.net.URL. Nuzno je da u korisnickim programima budu te klase importovane ako se koriste.
Metodi getCodeBase() i getDocumentBase()
Ako se ne zna tacan URL slike, ali se znate njeno ime i da se ona nalazi u istom direktoriju kao i applet, moze se koristiti varijanta metode getImage() koja uzima URL i ime datoteke. Koristite appletovu metodu getCodeBase() da dobijete URL appletovog direktorijuma:
Image img = this.getImage(this.getCodeBase(), "test.gif");
Metoda getCodeBase() vraca objekt tipa URL koji pokazuje na direktorijum iz kojeg je applet dosao.
Ali, ako je slika u istom direktorijumu kao i HTML datoteka, moze
se koristiti isti metod getImage(), ali sa getDocumentBase(). Vratice
se URL koji pokazuje na direktorijum u kojem se nalazi HTML stranica
koja je pozvala applet.
Image img = this.getImage(this.getDocumentBase(), "test.gif");
Ako se slika ucitava s Interneta, moze potrajati dok se ne ucita celokupna.
Ali se ona moze iscrtavati odmah nakon spajanja na neki od pomenutih
URLova. Java se stara za update kako podaci budu stizali, bez Vase intervencije.
Sve slike koje applet koristi ucitavaju se u metodi init(). Nije
dobra praksa da se ucitavaju unutar metoda paint() jer ce se svaki put
pri obnovi appleta, slike ucitavati iz pocetka!
Skaliranje slika
Prikaz slike u pravoj veličini
Jednom kad je slika učitana, može se prikazati u metodi paint() pomoću
metoda drawImage():
g.drawImage(img, x, y, io)
img je objekat klase Image koji je već učitan unutar metoda init().
x je apscisa, y ordinata gornjeg levog ugla slike.
io je objekat klase koja implementira interface ImageObserver.
Interface ImageObserver propisuje kako Java rukuje asinhronim obnavljanjem
slike kad se ona učitava sa udaljenog računara. S obzirom da klasa
java.applet.Applet implementira ImageObserver dovoljno je upotrebiti ključnu
reč this za odgovarajući argument metoda drawImage() čime se naznačuje
da se želi ipotrebiti ImageObserver trenutno aktivnog appleta.
Dakle, Vi sami ne pozivate metode ImageObservera, ali evo sadržaj definicije
interfejsa:
public interface ImageObserver {
public static final
int ABORT
public static int
final ALLBITS
public static final
int ERROR
public static int
final FRAMEBITS
public static final
int HEIGHT
public static int
final PROPERTIES
public static final
int SOMEBITS
public static int
final WIDTH
public boolean imageUpadte(Image
slika, int int2flegovi, int x, int y, int width, int height)
}
Interface poseduje jednu metodu imageUpadte. Ona otkriva sta je poyvano.
Interface ne morate sami implementirati, jer je to ucinjeno AWT klasom
komponent i svim njenim podklasama.
Digresija: Koncept interfejsa
u Java-i
Interfejsi su nacin
da se u javi nadoknadi funkcionalnost izgubljena eliminisanjem visestrukog
nasledjivanja. Interfejsi su slicni apstraktnim klasama u smislu da poput
apstraktnih klasa definišu šablon za korišćenje izvedenih klasa. Ali, postoje
i razlike, jer interfejsi, za razliku od klasa, nisu izvedeni od klase
Object, ali i mnogo značajnije jedna klasa može da implementira (nasledi)
više interfejsa.
Interfejsu su korisni ako se želi
označiti da če neke klase imati isto ponašanje, npr. proizvoditi iste zvučne
efekte kao znak uspeha, crtati linije iste boje,...
Dakle, interfejs predstavlja (slikovito
rečeno) obećanje neke klase da će implementirati određeni skup funkcija
definisan u interfejsu. Klase nasleđuju interfejs navođenjem kljušne reči
implements:
interface Kretanje {
public void Kreni()
{...}
public void Stani()
{...}
}
class Vozilo implements Kretanje {
public void Kreni()
{...}
public void Stani()
{...}
}
Interfejsi se mogu medjusobno
nasledjivati, npr. interface Kretati extends Kretanje {...}
Kada je interfejs definisan, moguce
je kreirati objekt u koji ce se smestiti bilo koja klasa koja implementira
dati interfejs:
public Kretanje VratiInterfejs() {...}
Kretanje k= VratiInterfejs();
k.Kreni();
k.Stani();
Klasa moze naslediti neku klasu, i implementirati
jedan ili vise interfejsa:
class Prva extends Klasa implements
PrviInterfejs {...}
class Druga extends Klasa implements
PrviInterfejs, DrugiInterfejs {...}
Interfejs moze sadrzati i promenljive,
preciznije konstante, jer sve "promenljive" u interfejsu implicitno dobijaju
modifikator static kao prefiks i vidljive su iz svih klasa koje implementiraju
dati interfejs.
Metoda paint() obavlja crtanja slike u pravoj veličini počevši od gornjeg
levog ugla:
public void paint(Graphics g) {
g.drawImage(img, 0, 0, this);
}
Skaliranje slika
Slika se moze skalirati unutar zadatog pravougaonika koristeci formu metode drawImage():
public boolean drawImage(Image img, int x, int y,
int width, int height, ImageObserver io)
img je objekat klase Image koji je već učitan unutar metoda init().
x je apscisa, y ordinata gornjeg levog ugla slike.
width i height su dimenzije pravougaonika u koji se zeli
smestiti slika.
io je objekat klase koja implementira interface ImageObserver.
Ako skaliranje nije u skladu s proporcijama slike, rezultat je
izobličen prikaz.
Izobličenje se može prevazići metodima getHeight() i getWidth() koje
daju pravu veličinu slike, te se ona može skalirati na odgovarajući
način. Na primer, ako se želi smanjiti na polovinu:
g.drawImage(img, 0, 0, img.getWidth(this)/2, img.getHeight(this)/2,
this);
Napisati aplet koji učitava sliku i uvećava je za zadati faktor:
import java.awt.*;
import java.applet.*;
public class Zum extends Applet {
private Image slika;
private int faktor;
/*Metoda init() čita dva parametra apleta od kojih jedan daje
ime slike, a drugi faktor povećanja.*/
public void init() {
String datotekaNaziv = this.getParameter("slikalokacija");
this.slika
= this.getImage(this.getCodeBase(), datotekaNaziv);
this.faktor = Integer.parseInt(this.getParameter("faktorskaliranja"));
}
/* Metoda paint() računa dimenzije i zatim crta skaliranu sliku.
*/
public void paint (Graphics g) {
int sirina = this.slika.getWidth(this);
int duzina = this.slika.getHeight(this);
int skaliranaSirina = sirina * this.faktor;
int skaliranaDuzina = duzina * this.faktor;
g.drawImage(this.slika, 0, 0, skaliranaSirina,
skaliranaDuzina, this);
}
}
<APPLET CODE="Zum.class" CODEBASE="http://www.matf.bg.ac.zu/~jelenagr/java/classes"
ARCHIVE="Zum.jar"
WIDTH=200 HEIGHT=200>
<param name="slikalokacija" value="slika.gif">
<param name="faktorskaliranja" value=2>
</APPLET>
Slika pre zumiranja
Slika nakon 2* zumiranja
Zašto je skaliranje vršeno u metodi paint(), a ne u metodi init(),
s obzirom da veličina slike se ne menja dinamički?
Zato što tokom izvršavanja metode init() slika verovatno neće biti
do kraja učitana, te metodi getWidth() i getHeight() će vratiti vrednost
koja utiče da skaliranje se neće obaviti.
Na primer:
import java.awt.*;
import java.applet.*;
public class Zum extends Applet {
Image slika;
int skaliranaSirina, skaliranaDuzina;
/*Metoda init() čita dva parametra apleta od kojih jedan daje
ime slike, a drugi faktor povećanja.*/
public void init() {
String datotekaNaziv = this.getParameter("slikalokacija");
slika = this.getImage(this.getDocumentBase(),
datotekaNaziv);
int faktor = Integer.valueOf(this.getParameter("faktorskaliranja")).intValue();
int sirina = slika.getWidth(this);
int duzina = slika.getHeight(this);
skaliranaSirina = sirina * this.faktor;
skaliranaDuzina = duzina * this.faktor;
}
/* Metoda paint() računa dimenzije i zatim crta skaliranu sliku.
*/
public void paint (Graphics g) {
g.drawImage(this.slika, 0, 0, skaliranaVisina,
skaliranaDuzina, this);
}
}