Pilt java programmis Pilt rakendis Rakendi ekraanile pildi manamiseks aitab rakendikäitur pildi kohale tuua rakendi meetodi getImage abil. Ekraanile saab ta joonistada klassi Graphics meetod drawImage. Meetodi neljas parameeter on komponent, kes hoolitseb pildi kohalelaadimise ning sellele järgneva joonistamise eest (siin näites rakend ise). import java.applet.Applet; import java.awt.*; import java.net.*; public class Pildirakend1 extends Applet{ public void paint(Graphics g){ Image pilt1=getImage(getCodeBase(), "summa.gif"); g.drawImage(pilt1, 0, 0, this); } } Joonistatava pildi suurust saab määrata joonistamise meetodis, kui lisaks algpunktile öelda ka joonistatava pildi pikkus ning laius. import java.applet.Applet; import java.awt.*; import java.net.*; public class Pildirakend2 extends Applet{ public void paint(Graphics g){ Image pilt1=getImage(getCodeBase(), "summa.gif"); g.drawImage(pilt1, 0, 0, getSize().width, getSize().height, this); } } Pilt rakenduses Iseseisvas programmis saab pildi osuti kätte klassi Toolkit meetodi getImage abil. Toolkit ise on abstraktne klass, temast pole võimalik isendi luua. Meetod getDefaultToolkit annab klassi Toolkit järglase isendi, kes oskab teha seda, mida klassi Toolkit isend peaks oskama. Paint-meetodis joonistatakse summamärgi pilt ekraanile, raami loomisel aga pannakse talle ikooniks õuna pilt. Java kohvitass on ikooniks vaid vaikimisi, kui see asendada, ei paista kaudsel vaatamisel kuidagi välja, et programm just java keeles tehtud on. import java.awt.*; import java.net.URL; public class Pilt1 extends Frame{ Image pilt=Toolkit.getDefaultToolkit().getImage("summa.gif"); public void paint(Graphics g){ g.drawImage(pilt, 0, 50, this); } public static void main(String argv[]){ Pilt1 raam=new Pilt1(); raam.setSize(300, 200); Image ikoon=Toolkit.getDefaultToolkit().getImage("oun.gif"); raam.setIconImage(ikoon); raam.show(); } } Rakend saab pilti võtta vaid sellest masinast, kus ta ise pärit on. Iseseisev programm võib pildi võtta ka mujalt Internetist. URL+i loomise lause tuleb panna püünisesse, sest juhul kui aadress on valesti kirjutatud, võib sellest kohast lendu minna erind. import java.awt.*; import java.net.URL; public class Pilt2 extends Frame{ Image pilt; public Pilt2(){ try{ pilt=Toolkit.getDefaultToolkit().getImage( new URL("http://www.tpu.ee/plogo.GIF") ); }catch(Exception e){ System.out.println("Probleem: "+e); } } public void paint(Graphics g){ g.drawImage(pilt, 0, 0, getSize().width, getSize().height, this); } public static void main(String argv[]){ Pilt2 raam=new Pilt2(); raam.setSize(300, 200); raam.show(); } } Muusikafailide mängimine Algusest peale ning ka praegu kõige kindamalt suudavad java programmid mängida au lihtsamas formaadis faile. Versioonist 1.2 on juurde liidetud ka muude (wav, midi) helifailitüüpide mängimise võimalus. Muusika mängimiseks tuleb luua AudioClip. Selle meetoditega play, loop ning stop saab panna klipi mängima ning mängimine katkestada. Loop tähendab, et klippi mängitakse pidevalt, s.t. pärast lõpetamist hakatakse mängimisega uuesti algusest peale. Keerulisemaid helisünteesi ning muid muusika juurde kuuluvaid valdkondi java keele juures alles luuakse (1999). import java.applet.*; public class Muusika1 extends Applet{ public void start(){ AudioClip lugu=getAudioClip(getCodeBase(), "spacemusic.au"); lugu.play(); } } Järgneva näite puhul hakatakse korduvalt mängima lehele tulles ning lehelt lahkudes lõpetatakse mängimine. import java.applet.*; public class Muusika2 extends Applet{ AudioClip lugu; public void init(){ lugu=getAudioClip(getCodeBase(), "spacemusic.au"); } public void start(){ lugu.loop(); } public void stop(){ lugu.stop(); } } Iseseisva programmi puhul saab klipi kätte klassi Applet staatilise meetodi newAudioClip abil, meetodi parameetriks on helifaili URL. import java.applet.*; import java.net.URL; public class Muusika3a{ public static void main(String argumendid[]) throws Exception{ AudioClip lugu=Applet.newAudioClip( new URL("http://minitorn.tpu.ee/~jaagup/kool/java/"+ "abiinfo/tutorial/sound/example-1dot2/bottle-open.wav") ); lugu.play(); Thread.sleep(5000); } } Kui soovitakse mängida lugu samast masinast, siis tuleb ka see kohalik aadress enne URLiks muuta. import java.applet.*; import java.net.URL; public class Muusika3{ public static void main(String argumendid[]) throws Exception{ AudioClip lugu=Applet.newAudioClip( new URL("file:"+System.getProperty("user.dir")+ "/spacemusic.au") ); lugu.play(); Thread.sleep(5000); } } Omatehtud joonised, komponendi loomine Omatehtud jooniste ning komponentide aluseks sobib lõuend (Canvas). Ta sobib lihtsaks joonistamiseks, kuid samas saab ta panna ka teateid vastu võtma, s.t. näiteks hiirevajutusele reageerima. Siin näites joonistatakse lõuendile soovitud nurkade arvuga hulknurk. Nurkade arvu saavad väljapoolsed muuta vaid meetodi abil. Iga muutmisega kaasneb uus joonistamine. import java.awt.*; public class Nurgad extends Canvas{ protected int nurkadearv; public Nurgad(){ nurkadearv=3; } public Nurgad(int uusarv){ nurkadearv=uusarv; } public void muudaNurkadeArv(int uusarv){ nurkadearv=uusarv; repaint(); } public void paint(Graphics g){ int korgus=getSize().height; int laius=getSize().width; double nurgavahe=2*Math.PI/(double)nurkadearv; int raadius=Math.min(korgus, laius)/3; int keskx=laius/2; int kesky=korgus/2; int vanax=keskx; int vanay=kesky+raadius; int uusx, uusy; for(int i=1; i<=nurkadearv; i++){ uusx=keskx+(int)(raadius*Math.sin(i*nurgavahe)); uusy=kesky+(int)(raadius*Math.cos(i*nurgavahe)); g.drawLine(vanax, vanay, uusx, uusy); vanax=uusx; vanay=uusy; } } } Loodud komponenti saab kasutada seal, kus vaja hulknurki joonistada. Siin näites pannakse rakendi ekraanile üheksa hulknurka, nurkade arvuga kolmest üheteistkümneni. import java.applet.Applet; public class Nurgarakend extends Applet{ public void init(){ setLayout(new java.awt.GridLayout(3, 3)); for(int nr=3; nr<12; nr++){ add(new Nurgad(nr)); } } } Samuti saab loodud komponendi abil lasta kasutajal valida, mitme nurgaga hulknurka soovib. Selleks panin rakendile kerimisriba ning loodud komponendi. Rakendi panin kerimisriba kuulajaks (AdjustmentListener). Kui kerimisriba määratud koha väärtust muudetakse, siis saadetakse uus väärtus rakendile, kes selle omakorda saadab hulknurka joonistavale komponendile. import java.applet.Applet; import java.awt.*; import java.awt.event.*; public class Nurgarakend2 extends Applet implements AdjustmentListener{ Nurgad ng=new Nurgad(); Scrollbar sb=new Scrollbar( Scrollbar.VERTICAL, 3, 2, 2, 20 ); public void init(){ setLayout(new BorderLayout()); add("West", sb); add("Center", ng); sb.addAdjustmentListener(this); } public void adjustmentValueChanged(AdjustmentEvent e){ ng.muudaNurkadeArv(e.getValue()); } } Graphics2D Põhilised joonistamisfunktsioonid on klassis java.awt.Graphics. Alates versioonist 1.2 pakub laiendatud joonistamisvõimalusi eelmise alamklass Graphics2D. Kui esimesel juhul tuli alati arvutada ekraanikoordinaatides ning joone laiuseks oli üks punkt, siis siin võib valida omale sobiva taustsüsteemi ning ka joonistamisel saab enam parameetreid määrata. Kuna Graphics2D on klassi Graphics alamklass, siis ta oskab kõike mida eellanegi ning vajadusel saab temaga joonistada samade meetoditega, mis klassist Graphics omale sisse harjunud. Ühilduvuse huvides on komponendi meetodi paint parameetriks endiselt Graphics, kuid tegelikult antakse sellesse meetodisse joonistamiseks isend, kes suudab ka Graphics2D klassis kirjeldatud operatsioone täita. Juhul, kui spetsiifilisi omadusi vajatakse, tuleb muutuja tüüp enne teisendada. Joone omadused Joone tõmbamisel saab Graphics2D juures klassi BasicStroke abil määrata joone laiust, otsa kuju ning kahe joone ühendust (võimalused leiad API dokumetatsioonist). import java.awt.*; public class Joon1 extends Canvas{ public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; float laius=15; int jooneots=BasicStroke.CAP_ROUND; int uhendus=BasicStroke.JOIN_BEVEL; g.setStroke(new BasicStroke(laius, jooneots, uhendus)); g.drawRect(10, 10, 70, 100); g.drawLine(100, 10, 140, 200); } } Joonistusala piiramine Joonistamisala on võimalik piirata käsuga clip, andes ette kujundi, mille piires tohib joonistada. Siin näites määratakse joonistamise alaks ellipsi pind ning seejärel joonestatakse seest täidetud ristkülik. Tulemusena tekib ekraanile vaid ellipsi ning ristküliku ühisosa. import java.awt.*; import java.awt.geom.*; public class Kujund1 extends Canvas{ public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; Shape kujund=new Ellipse2D.Float(10, 10, 300, 100); g.clip(kujund); g.fillRect(20, 20, 400, 60); } } Venitamine, keeramine Joonistuspinda saab liigutada, venitada ja keerata. AffineTransform'i abil saab määrata, kuidas ja kui palju. Esimese näite puhul lükatakse koordinaatide alguspunkti saja ühiku võrra paremale ning alla. import java.awt.*; import java.awt.geom.AffineTransform; public class Transform2 extends Canvas{ public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; g.setTransform(AffineTransform.getTranslateInstance(100, 100)); g.fillRect(20, 20, 40, 20); } } rida g.setTransform(AffineTransform.getScaleInstance(3, 1.5)); suurendab joonist x-telje suunas 3 ning y-suunas 1,5 korda. g.setTransform(AffineTransform.getRotateInstance(Math.PI/4, 100, 75)); keerab joonist Pi/4 ehk 45 kraadi võrra ümber punkti 100, 75 g.setTransform(AffineTransform.getShearInstance(Math.PI/4, 0)); keerab püsttelge Pi/4 võrra. Kui soovida mitut muutust üheskoos, siis võib luua AffineTransform tüüpi isendi ning talle soovitud muutusi järjekorras rakendada. import java.awt.*; import java.awt.geom.AffineTransform; public class Transform6 extends Canvas{ public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; AffineTransform tr=new AffineTransform(); tr.rotate(Math.PI/4, 50, 100); tr.translate(150, 0); g.setTransform(tr); g.fillRect(20, 20, 40, 20); } } Muster, värviüleminek Joonistamisel saab lisaks ühele värvile soovi korral pinda katta ka nii värviülemineku kui piltidest koostatud mustriga. Soovitud katmisstiil tuleb määrata Graphics2D meetodiga setPaint. Värviülemineku andmeid kannab GradientPaint. Konstruktoris tuleb määrata kaks punkti ning kummagi punkti juurde kuuluv värv. Nendes punktides vastab joonise värv sinna määratud värvile, punkte ühendaval sirget mööda muutub värv sujuvalt ühest värvist teiseks. Tavajuhul jääb kummagi punkti "selja taha" punktile vastav värv, kuid kui lisada konstruktorisse tõeväärtusmuutuja, siis saab panna värvi tsükliliselt lainetama nii, et laine pikkuseks jääb kahe punkti vahe. import java.awt.*; import java.awt.geom.*; public class Kujund2a extends Canvas{ public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; g.setPaint(new GradientPaint(0, 100, Color.yellow, getSize().width, 100, new Color(0, 200, 100) )); g.fillRect(0, 0, getSize().width, getSize().height); } } Pinna mustriga katmisel tuleks kasutada klassi TexturePaint võimalusi, andes konstruktorile parameetriks pildi millega katta, lisaks ka pildi suuruse ja asukoha, millest alates pilte kõrvuti laduda. Kujundi äärejooned Kujundi (näiteks ellipsi) äärejooned annab BasicStroke meetod createStrokedShape. Nii näiteks on võimalik kujundist vaid äärejooned välja joonistada või siis teise värviga esile tuua. public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; BasicStroke b1=new BasicStroke(15); Shape kujund=b1.createStrokedShape( new Ellipse2D.Float(100, 100, 50, 70) ); g.fill(kujund); g.setColor(Color.green); g.draw(kujund); } Kuna nii ellips on kujund ning ka jämedajoonelise ellipsi äärejooned on samuti kujundid, siis juhul, kui annan äärejoontele jämeduse, võin ka nendelt omakorda äärejooned küsida. Nii saan tulemuseks juba neli joont: kaks üksteisele lähedal asuvat ovaali sees ning teised kaks ovaali välisringis. public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; BasicStroke b1=new BasicStroke(15); BasicStroke b2=new BasicStroke(3); Shape kujund=b1.createStrokedShape( new Ellipse2D.Float(100, 100, 50, 70) ); Shape kujund2=b2.createStrokedShape(kujund); g.draw(kujund2); } Kui sooviksin nende joontega midagi eraldi teha, näiteks neid igaüht isevärvi värvida, siis on mul võimalik kujund joonteks jagada klassi PathIterator abil. Selle abil saan kätte iga joone andmed. Sirgjoonel piisab kahest punktist. Kolme punkti abil määratakse kõverjoon, kus kaks punkti on otspunktideks ning kolmas näitab, milline peab kaar tulema. Nelja punktiga määratud joone puhul on samuti kaks otspunktideks, ülejäänud kahe punkti abil aga määratakse joone suunda otspunktist väljumisel. Uusi kujundeid aitab kombineerida klass GeneralPath. Talle tuleb lihtsalt öelda millise koha peale joon või ring või muu olemasolev kujund paigutada. Kriipsujuku saab tema abil küllalt kergesti valmis ning siis võib seda kasutada nagu iga muud kujundit. public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; GeneralPath gp=new GeneralPath(); gp.append(new Ellipse2D.Float(20, 50, 40, 40), false); gp.append(new Line2D.Float(40, 100, 40, 150), false); g.draw(gp); } Pilditöötlus Image on java jaoks nii väljastpoolt failist võetud kui ise joonistatud pilt. Tühja pildi joonistamiseks saab luua meetodi createImage abil. Image osutab pildi andmetele, tema kaudu saab pilti kusagil näidata. Pildi muutmiseks tuleb pildilt küsida klass Graphics (või tema alamklass Graphics2D). Selle nn. graafilise konteksti juures on meetodid, mille abil saab pildile midagi (juurde) joonistada. Valmis pilti kuhugile joonistades saab määrata tema kõrgust ja laiust, Graphics2D abil ka keerata või venitada. Võib mitmest pildist ühe kokku kombineerida ning sinna vajadusel jooni, ringe ja muid kujundeid juurde joonistada. Keerulisemate kujundite loomisel on kiiremaks mooduseks ta mälus punkti kaupa välja arvutada ning siis loodud massiivist pilt luua. Nii saab näiteks värviüleminekute juures ilusti igale punktile värvi arvutada ning hoolitseda, et ükski punkt värvita ei jääks. Pilti arvudeks muutes saab pildi andmed näiteks faili salvestada või Interneti kaudu teisele kasutajale saata. Ka on selle abil võimalik pilti analüüsida. Kui pildi käest andmed küsida ning pärast nende muutmist andmetest uus pilt luua, siis saab pilti päris mitut moodi mõjutada. Võib ühe värvi teisega asendada, kujundite piirpindu silendada või teravdada. Suurema mõttetöö korral ka olemasolevast pildist kujundeid eraldada ning nendega omaette midagi ette võtta (näiteks raamatust kopeeritud pildist teksti välja lugeda). Animatsiooni puhul on mõistlik uus ekraanipilt enne mälus valmis teha ning alles siis ekraanile joonistada. Sellisel juhul ei hakka pilt uue kujundi loomise ajal vilkuma. Animatsioon võtab suhteliselt palju ressursse, kuid võtete abil saab liikumist näidata ka aeglasema arvuti peal. Kui taust püsib paigal ning vaid esiplaani kujund liigub, siis piisab tausta korra valmistamisest ning iga uue pildi loomiseks joonistada taust alla ning kujund sobivasse kohta peale. Veelgi enam: piisab, kui taust joonistada vaid selle osa peale, kus liikuv kujund viimati oli (meetod clip laseb määrata, millisesse pildi piirkonda joonistada, mujale suunatud joonistuskäsud jäävad täitmata). Kui liikumine piirdub vaid mõne(teistkümne) pildi vahetamisega, siis on mõistlikum pildid enne välja arvutada/joonistada ning siis ükshaaval ringis vahetada.