540 likes | 821 Views
Applety. princípy fungovania appletu, čo applet môže, a čo nie..., applet na web-stránke, kreslenie v applete, grafická knižnica java.awt : p reh ľad základných komponentov: B utton, T ext Field , combo-box, …. schémy rozmiestnenia, tzv. layouts : BorderLayout, GridLayout, ...
E N D
Applety • princípy fungovania appletu, • čo applet môže, a čo nie..., • applet na web-stránke, • kreslenie v applete, • grafická knižnica java.awt: • prehľad základných komponentov: Button, TextField, combo-box, …. • schémy rozmiestnenia, tzv. layouts: BorderLayout, GridLayout, ... • spracovanie udalostí: eventy, listenery, ... Zdroj a literatúra: • Thinking in Java, 3rd Edition, 14.kapitola, • Java Applet Tutorial and Demos, • CZ: Naučte se Javu, Applety v Jave, • demo z prednášky Cvičenia: jednoduché applety s interakciou: • maľovátko, euro-kalkulačka, • logické hry: pexeso, piškvorky, ... • dynamické hry: tenis, arkády, ...
GUI Ak chceme vytvoriť grafickú aplikáciu v Jave, vzhľadom na multi-plaformovosť jazyka, hľadáme multi-platformovú GUI knižnicu: • AWT používa obmedzenú množinu komponentov, ktoré sa renderujú v závislosti na operačnom systéme, kde bežia, teda iný OS, iný look • Swing podporovaný napr. v NetBeans, vylepšil AWT pri zachovaní filozofie, aplikácia používa svoj vlastný look • SWT od fy. IBM, podporovaný v Eclipse (http://eclipse.org/swt/) potrebuje na spustenie knižnicu, obmedzená mulfi-platformovosť Aplikáciu môžeme vytvoriť skladaním a umiestňovaním vizuálnych komponentov • NetBeans, IntelliJ IDEA, JBuilder alebo manuálne • to si ukážeme, aby sme pochopili jednotlivé konštrukcie
Prvý… applet je podtrieda triedy java.applet Applet1.html: . . . <applet code=Applet1 width=200 height=200> </applet> . . . import java.applet.*; // podtrieda triedy java.applet import java.awt.*;// grafická knižnica AWT publicclass Applet1 extends Applet { // paint je metóda, ktorá pre/vy-kreslí applet publicvoidpaint(Graphics g) { g.drawString("Moj prvy applet", 10, 10); } } appletviewer file:C:\borovan\java\eclipse\Applet1\Applet1.html Súbor: Applet1.java
Druhý… • applet je jedna z možností, ako vyrobiť aplikáciu s GUI • knižnica AWT je jedna z možností pre tvorbu GUI import java.awt.*; import java.applet.*; publicclass Applet2 extends Applet { publicvoidpaint(Graphics g) { g.drawString("Druhy applet", 10, 15); g.draw3DRect(0, 0, 100, 20, true); } } • Applet spustíme: • najľahšie vo vývojovom prostredí (napr. Eclipse) počas ľadenia (Alt+Shift+X,A), • pomocou appletviewer-a, ktorému podhodíme html stránku s tagom <applet>, (appletviewer je súčasťou JDK, máte ho v bin adresári javy), • pomocou browsera, ktorý však už v sebe má nainštalovaný správny runtime javy, • (ak nemá, tak vás o to požiada pri klepnutí na stránku obsahujúcu applet, nainštalujete pluggin). Súbor: Applet2.java
Ako vyrobíme applet tag do html kódu stránky, kam chceme applet vložiť, vložíme applet tag: <APPLET CODE = hlavná trieda Appletu, napr. “Prvy“, resp. “Druhy.class“ WIDTH = šírka okna v html stránke (v pixloch), HEIGHT = výška okna v pixloch nepovinné: NAME = logické meno appletupoužiteľné iným appletom v rámci browsera, CODEBASE = url, resp. adresár odkiaľ sa budú ťahať zvyšné .class súbory, v opačnom prípade je to url/adresár, kde je html súbor, ARCHIVE = url na java archive file .jar (spakovaná aplikácia), ALIGN = zarovnanie appletu, napr: left, right, top, ... HSPACE/VSPACE = vodorovné/zvislé odsadenie v pixeloch. > parametre appletu (niečo ako args pre klasickú aplikáciu): [ <PARAM NAME = meno VALUE = hodnota> ] </APPLET>
Applet nemôže všetko • applet je kód, ktorý sa zväčša stiahne zo servera a beží v browseri u klienta, • z bezpečnostných dôvodov, applet a aplikácia majú iné práva a riadenie, • existujú java aplikácie, ktoré majú GUI (odovodené od triedy Frame) – neskôr.. • aj keď práva appletu sú nastaviteľné (viď .java.policy súbor), • štandardné nastavenia ochrany majú výhody a obmedzenia: obmedzenia z bežpečnostných dôvodov: • nemôže písať do filesystému na strane klienta (v browseri), • nemôže spúšťať programy, • nemôže vytvárať spojenia na iný server ako ten, odkiaľ pochádza, • môže získať len čiastočnú informáciu o klientskom systéme. • výhody: • applet nepotrebuje inštaláciu (skoro), • applet vám nezničí systém, • do browsera sa natiahne pôvodný applet bez informácie o predošlom behu, • applet v browseri može zobrazovať iné html stránky, prehrávať zvuky, ... • idea nezávislej platformy • pravidlo 23: váš applet si vyskúšajte: • aspoň v dvoch browseroch, • pod dvomi operačnými systémami, • ideálne aj s dvomi java-runtime.
Ako applet píše na disk publicclass WritingApplet extends Applet { publicvoid paint(Graphics g) { String fileName = "WritingApplet.txt"; try { FileOutputStream out = new FileOutputStream(fileName); PrintStream outf = new PrintStream(out); outf.println("i'am writing..."); outf.close(); out.close(); g.drawString("finito", 10, 10); } catch (Exception e) { g.drawString(e + "", 10, 10); } } } Keďže každé pravidlo má svoje výnimky, ukážeme si, ako applet môže písať na disk ... so súhlasom klienta... vhodne umiestnený súbor .java.policy na klientskej strane (c:\windows\user) grant codeBase "file:/c:/borovan/eclipse/09_java/bin/" { permission java.io.FilePermission "<<ALL FILES>>", "write"; }; .java.policy súbor editujeme pomocou aplikácie policytool viac na http://java.sun.com/sfaq/ Súbor: WritingApplet.java
Život appletu void addItem(String newWord) { System.out.println(newWord); buffer.append(newWord); repaint(); } public void paint(Graphics g) { // pri každom prekreslení, resize appletu. g.drawRect(0, 0, size().width-1, size().height-1); g.drawString(buffer.toString(), 5, 15); } } init... start... stop... destroy... public class Applet5 extends Applet { StringBuffer buffer; public void init() { // applet je prvý krát vytvorený, po reload buffer = new StringBuffer(); addItem("init... "); } public void start() { // applet je spustený web browseorm, po refresh addItem("start..."); } public void stop() { // web browser opustí stránku, resp. appletviewer zastaví applet addItem("stop..."); } public void destroy() { // pri uvoľnení resourcov appletu, reload stránky addItem("destroy..."); } Súbor: Applet5.java
Grafika • dnes používame grafickú knižnicu java.AWT, iná alternatíva je java.SWING, • na kreslenie do appletu (do triedy java.awt.Canvas) použijeme metódy triedy java.awt.Graphics, najlepšie v metóde paint(Graphics g), príklad Applet6 ilustruje základné metódy: • g.drawLine(x1,y1,x2,y2) – čiara z [x1,y1] do [x2,y2], • g.drawRect(x,y,w,h), draw3DRect(x,y,w,h,raised) – obdĺžnik [x,y], [x+w,y+h], • g.drawRoundRect(x,y,w,h,arc_w,arc_h) – zaoblený obdĺžnik, • g.drawOval(x,y,w,h) – elipsa, • g.drawArc(x,y,w,h,a1,a2) – oblúk od uhla a1 po a2, • Polygon polygon = new Polygon(); • polygon.addPoint(x, y); • g.drawPolygon(polygon); príklad Nuhol kreslí všetky uhlopriečky pravidelného N-uholníka okrem tých, čo prechádzajú stredom, N je argument appletu zadaný v html, Turtle je o korytnačej grafike. Off-line spôsobom kreslíme do objektu Image img = createImage(), metóda paint potom prekreslí do appletu celý Image img.
g.drawLine(x1,y1,x2,y2); • g.drawRect(x,y,w,h); • g.draw3DRect(x,y,w,h,raised); • g.drawRoundRect(x,y,w,h,arc_w,arc_h); • g.drawOval(x,y,w,h); • g.drawArc(x,y,w,h,a1,a2); • Polygon polygon = new Polygon(); • polygon.addPoint(x, y); • g.drawPolygon(polygon); java.Graphics Súbor: Applet6.java
Uhlopriečky for(int i=0;i<N; i++) for(int j=i;j<N; j++){ if (2*(j-i) == N) continue; g.drawLine(X[i],Y[i],X[j], Y[j]); } } public classNuhol extends Applet { static int N; publicvoid start() { try { // čítanie parametra appletu N=Integer.parseInt(getParameter("N")); } catch (Exception e) {N = 4;} } public voidpaint(Graphics g) { int sx = getWidth() / 2; int sy = getHeight() / 2; int rad = ((sx>sy)?sy:sx)*2/3; int X[] = new int[N];// pole x-suradnic int Y[] = new int[N]; // pole y-suradnic // trochu matiky = výpočet súradníc vrcholov for(int i=0; i<N; i++) { X[i] = (int)Math.round(sx+rad* Math.cos((float)i*2*Math.PI/N)); Y[i] = (int)Math.round(sy+rad* Math.sin((float)i*2*Math.PI/N)); } Súbor: Nuhol.java
Korytnačka public class Turtle extends Applet { float X, Y, dir; // momentálny stav korytnačky Image img; // vytvorenie off-line image v pamäti public void init() {// inicializácia img img = createImage(getWidth(),getHeight()); } public void Dopredu(float Dlzka) { float X1 = X + (float)(Dlzka*Math.cos(dir*2*Math.PI/360));// trochu matiky float Y1 = Y + (float)(Dlzka*Math.sin(dir*2*Math.PI/360)); // sin, cos, … img.getGraphics().// kreslenie do img drawLine((int)X,(int)Y,(int)X1,(int)Y1); X = X1; Y = Y1; } public void paint(Graphics g) { //zobrazenie img z pamäte g.drawImage(img,0,0,Color.YELLOW,this); } // korytnačí program public void start() { ZmenXY(100,100); for(int i=0; i<150; i++) { Dopredu(150); Vlavo(179); } repaint(); } }
Opitý námorník public void init() {// opitý námorník je vlákno namornik = new Namornik(this);// vytvoríme ho bufImage = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_ARGB); } public void start() { namornik.start();// opitý námorník štartuje } public void paint(Graphics g) { Graphics bg = bufImage.getGraphics();// kreslíme do obrázka v pamäti bg.setColor(new Color(255,255,255));// zmaž pozadie bg.fillRect(0, 0, sizeX, sizeY); bg.setColor(new Color(200,200,100));// nakresli mólo bg.fillOval(centerX - scale * moloSize, centerY - scale * moloSize, scale * 2 * moloSize, scale * 2 * moloSize); namornik.paint(bg); // nakresli námorníka g.drawImage(bufImage, 0, 0, this);// zobraz obrázok z pamäte v applete } Súbor: NamornickyApplet.java
Utopený námorník Vlákno Namornik okrem toho, že počíta momentálnu polohu optitého námorníka definuje aj metódu paint() podobnú appletovskej, ktorá zobrazí námorníka na móle, ak ešte žije. Ak nie, len vlnky in memoriam... public void paint(Graphics g) { if (alive) // ak sa ešte neutopil, //nakresli obrázok námorníka g.drawImage(namornik, getXPixel(false), getYPixel(false), molo); else { // ak už je utopený, nakresli vlny g.setColor(Color.RED);// zobraz v strede vĺn počet krokov g.drawString(Integer.toString(nsteps), getXPixel(true)-8, getYPixel(true)+7); g.setColor(Color.BLUE); // kresli vlny int nwaves = 7; // koľko vĺn nakresliť for (int i = 3; i <= nwaves; i++) // vnútorné 2 vlny sa nekreslia g.drawOval(getXPixel(true) - i * waves / nwaves, getYPixel(true) - i * waves / nwaves, i * 2 * waves / nwaves, i * 2 * waves / nwaves); } Súbor: Namornik.java
AWT-komponenty • AWT knižnicu možno chápať ako podmnožinu alternatívnej SWING, • obsahuje základné triedy: Canvas, Panel, ... • komponenty: Button, Label, TextArea, TextField, CheckBox, Choice, List, ... • práca s komponentami je ilustrovaná na nasledujúcich príkladoch, • väčšina ideí aj riešení je priamo prepísateľná do farbistejšej verzie SWINGu – možete používať vo vaších riešeniach, • rozmiestnenie komponentov v jednotlivých paneloch je dané layout-om: • BorderLayout – 5 častí North, East, South, West, Center, • GridLayout – mriežka MxN, • FlowLayout – voľný formát, • CardLayout – karty so záložkami, • existujú dva spôsoby, ako sa spracovávajú udalosti od týchto komponentov: • event-handler – centrálna rutina spracovávajúca istý druh udalostí (napr. myš), • listerner – špeciálna trieda s vlastnosťami (properties a la Delphi).
Gombíky Najjednoduchší príklad appletu s tromi objektami triedy Button, ktorému v konštruktore možeme zadať popis na gombík. Rozloženie v hlavnom paneli appletu je defaultné, t.j. Flow. Možeme na ne klikať, ale nikto nespracováva udalosti takto generované. import java.awt.*; import java.applet.*; publicclass Button1 extends Applet { Button b1 = new Button("Button 1"), b2 = new Button("Button 2"), b3 = new Button("Button 3"); publicvoid init() { add(b1); add(b2); add(b3); } } • Gombík ako objekt treba: • vytvoriť (b=new Button(“…”)), • vložiť do panelu add(b) Súbor: Button1.java
Udalosti import java.awt.*; import java.applet.*; publicclass Button3 extends Applet { Button b1 = new Button("Play"), b2 = new Button("Loop"), b3 = new Button("Stop"); publicvoid init() { add(b1); add(b2); add(b3); } publicboolean action(Event evt, Object arg) { if(evt.target.equals(b1)) getAudioClip(getCodeBase(),"Startup.wav").play(); elseif(evt.target.equals(b2)) getAudioClip(getCodeBase(),"Startup.wav").loop(); elseif(evt.target.equals(b3)) getAudioClip(getCodeBase(),"Startup.wav").stop(); else returnsuper.action(evt, arg); returntrue; } } • metóda action() odchytáva udalosti ako stlačenie gombíka, výber zo zoznamu, combo-boxu, ... • z jej argumentov je možné zistiť, ktorý objekt vygeneroval udalosť a akú, • v tomto príklade sa udalosti spracujú tak, že sa (opakovane) prehrá, či zastaví audiosúbor .wav, .au, oživenie vašich hier Súbor: Button3.java
Obrázok import java.awt.*; import java.applet.*; publicclass Button4 extends Applet { Button b1 = new Button("x"), b2 = new Button("o"); Image img;// obrázok, ktorý sa načíta publicvoid init() { add(b1); add(b2);} publicvoid paint(Graphics g) {// vykreslenie obrázka g.drawImage(img,1,1,Color.YELLOW,this); } publicboolean action(Event evt, Object arg) { if(arg.equals("x")) {// čítanie obrázka .jpg img = getImage(getCodeBase(), "images/x.jpg"); elseif(arg.equals("o")) // čítanie obrázka .gif img = getImage(getCodeBase(), "images/o.gif"); else returnsuper.action(evt, arg); repaint(); returntrue; } } • z hľadiska spracovania udalosti sa táto verzia odlišuje len minimálne, netestujeme evt.target ale hodnotu parametra arg, • príklad ilustruje možnosť načítať obrázok .gif, .jpg, .bmp a zobraziť ho v applete • obrázok sa načíta do objektu Image a zobrazí pomocou drawImage, podobne ako Namorník.java Súbor: Button4.java
Listener public class Button2 extends Applet { Button b1 = new Button("Play"), b2 = new Button("Loop"), b3 = new Button("Stop"); AudioClip audioClip; public void init() { audioClip =getAudioClip(getCodeBase(), "Startup.wav"); b1.addActionListener(new B1());add(b1); b2.addActionListener(new B2());add(b2); b3.addActionListener(new B3());add(b3); } classB1implementsActionListener { public voidactionPerformed(ActionEvent e) { audioClip.play(); } } classB2implementsActionListener {...} classB3implementsActionListener {...} } • funkčná analógia appletu Button4, len inak ošetrené udalosti, • pre každý komponent b1, b2, b3 definujeme extra triedu, ktorá sa správa ako ActionListener, • ActionListener musí mať definovanú metódu void actionPerformed(), • actionPerformed() sa volá, ak nastane udalosť na komponente, • aby komponent tušil, kto je jeho ActionListener, nezabudnite ho naviazať na komponent pomocou metódy addActionListener – častá chyba v začiatkoch, • B1, B2, B3 sú triedy, ktoré špecifikujú vlastnosti (properties) daného komponentu. V tomto príklade je to actionPerformed() (onClick) Súbor: Button2.java
TextField publicclass TextField1 extends Applet { Button b1 = new Button("Get Text"), b2 = new Button("Set Text"); TextField t = new TextField("Starting text", 20); String s = new String(); publicvoid init() { add(b1); add(b2); add(t); } publicboolean action (Event evt, Object arg) { if (evt.target.equals(b1)) { getAppletContext().showStatus(t.getText()); s = t.getSelectedText(); if(s.length() == 0) s = t.getText(); t.setEditable(true); } elseif (evt.target.equals(b2)) { t.setText("Inserted by Button 2: " + s); t.setEditable(false); } elsereturnsuper.action(evt, arg); returntrue; } } • TextField je jednoriadkový “editbox”, • základné vlastnosti: • setEditable(), • setText(), • getText(), • getSelectedText() Súbor: TextField1.java
publicclass TextArea1 extends Applet { Button b1 = new Button("Get"); Button b2 = new Button("Insert"); Button b4 = new Button("Replace"); TextArea t1 = newTextArea("text1", 1, 30); TextArea t2 = new TextArea("text2", 4, 30); publicvoid init() { add(b1); add(t1); add(b2); add(t2); add(b4);} publicboolean action (Event evt, Object arg) { if(evt.target.equals(b1)) getAppletContext().showStatus(t1.getText()); elseif(evt.target.equals(b2)) { t2.setText("Inserted by Button 2"); t2.append(": " + t1.getText()); getAppletContext().showStatus(t2.getText()); } elseif(evt.target.equals(b4)) t2.replaceRange("Replaced", 0, t2.getText().length()); elsereturnsuper.action(evt, arg); returntrue; } } Text area • TextArea je viac-riadkový TextField Súbor: TextArea1.java
publicclass Label1 extends Applet { Label labl2 = newLabel(" "); Label labl3 = new Label(" ", Label.RIGHT); Button b1 = new Button("Test 1"); Button b2 = new Button("Test 2"); publicvoid init() { add(b1); add(labl2); add(b2); add(labl3); } publicboolean action (Event evt, Object arg) { if(evt.target.equals(b1)) labl2.setText("set text"); elseif(evt.target.equals(b2)) { if(labl3.getText().trim().length() == 0) labl3.setText("labl3"); if(labl3.getAlignment() == Label.LEFT) labl3.setAlignment(Label.CENTER); elseif(labl3.getAlignment()==Label.CENTER) labl3.setAlignment(Label.RIGHT); elseif(labl3.getAlignment() == Label.RIGHT) labl3.setAlignment(Label.LEFT); } elsereturnsuper.action(evt, arg); returntrue; } } Label • trieda Label: • setText(), • getText(), • setAlignment(), • getAlignment(). Súbor: Label1.java
publicclass CheckBox1 extends Applet { TextArea t = new TextArea(6, 20); Checkbox cb1 = newCheckbox("Check Box 1"); Checkbox cb2 = new Checkbox("Check Box 2"); publicvoid init() { add(t); add(cb1); add(cb2); add(cb3); } publicboolean action (Event evt, Object arg) { if(evt.target.equals(cb1)) trace("1", cb1.getState()); elseif(evt.target.equals(cb2)) trace("2", cb2.getState()); else returnsuper.action(evt, arg); returntrue; } void trace(String b, boolean state) { if(state) t.append("Box " + b + " Set\n"); else t.append("Box " + b + " Cleared\n"); } } CheckBox • trieda CheckBox: • setState(), • getState(). Súbor: CheckBox1.java
RadioButton publicclass RadioButton1 extends Applet { TextField t = new TextField("Radio button 2", 30); CheckboxGroup g = new CheckboxGroup(); Checkbox cb1 = newCheckbox("one", g, false), cb2 = new Checkbox("two", g, true); publicvoid init() { t.setEditable(false); add(t); add(cb1); add(cb2); } publicboolean action (Event evt, Object arg) { if(evt.target.equals(cb1)) t.setText("Radio button 1"); elseif(evt.target.equals(cb2)) t.setText("Radio button 2"); else returnsuper.action(evt, arg); returntrue; } } • ak potrebujeme vytvoriť tzv. radio button, vytvoríme objekt CheckboxGroup, do ktorého vložíme CheckBoxy, ktoré sú navzájom exkluzívne. Súbor: RadioButton1.java
publicclass Choice1 extends Applet { String[] description = { "Sokol", "Orol", "Sova", "Cajka", "Havran", "Jastrab", "Sup" }; TextField t = new TextField(20); Choice c = new Choice(); Button b = new Button("Add next"); int count = 0; publicvoid init() { t.setEditable(false); for(int i = 0; i < 4; i++) c.addItem(description[count++]); add(t); add(c); add(b); } publicboolean action (Event evt, Object arg) { if(evt.target.equals(c)) t.setText(c.getSelectedIndex()+" "+(String)arg); elseif(evt.target.equals(b)) { if(count < description.length) c.addItem(description[count++]); } else returnsuper.action(evt, arg); returntrue; } } Combo • trieda Choice implementuje combo-box, • položky sa pridávajú pomocou addItem() • ak chceme zistiť, ktorú položku bola vybratá, pomocou metódy getSelectedIndex() Súbor: Choice1.java
Combo2 public class AppletCommunication extends Applet { public void start() { // dostane kolekciu vsetkych sucasne beziacich appletov Enumeration<Applet> e = getAppletContext().getApplets(); // a nahadze ich kvoli vizualizacii do combo-boxu Choice lst = new Choice(); while (e.hasMoreElements()) lst.addItem(e.nextElement().getClass().getName()); add(lst); // pridaj combo do appletu add(new Button("play as Button3")); // pridaj gombík } // toto reaguje na akykolvek event, nie len Button, public boolean action(Event evt, Object arg) { Button3 ap =// vzdialený applet ako objekt (Button3)getAppletContext().getApplet("Button3"); ap.play("Startup.wav"); // volanie metódy play z return true; // appletu Button3 } } AppletCommunication v combo-boxe obrazí všetky zároveň bežiace applety v otvorenom okne browsera. Na akúkoľvek udalosť, t.j. aj na stlačenie gombíka “Play as Button3” zavolá metódu play() z appletu Button3, ktorá prehrá známu Windows hymnu. To je ilustrácia techniky, ako môžu dva súčasne bežiace applety "komunikovat" medzi sebou, t.j. spúsťať si navzájom svoje metódy. Súbor:AppletCommunication.java
publicclass List1 extends Applet { String[] flavors = { "Cokolada", "Visna", "Ceresna", "Pistacia", "Rum", "Jahoda","Malina", "Hrozno" }; List lst = new List(6, true); TextArea t = new TextArea(flavors.length, 30); Button b = new Button("test"); int count = 0; publicvoid init() { t.setEditable(false); for(int i = 0; i < 4; i++) lst.add(flavors[count++]); add(t); add(lst); add(b); } publicboolean action (Event evt, Object arg) { if(evt.target.equals(lst)) { t.setText(""); String[] items = lst.getSelectedItems(); for(int i = 0; i < items.length; i++) t.append(items[i] + "\n"); } elseif(evt.target.equals(b)) { if(count < flavors.length) lst.add(flavors[count++], 0); } else returnsuper.action(evt, arg); returntrue; } } List Box • multiple-choice listbox vytvoríme pomocou triedy List (počet riadkov, true=multiple choice), • položky pridávame add(), • getSelectedItems() je pole označených položiek, alebo getSelectedIndexes(), getSelectedObjects(), Súbor: List1.java
FlowLayout import java.awt.*; import java.applet.*; publicclass FlowLayout1 extends Applet { publicvoid init() { setLayout(new FlowLayout()); for(int i = 0; i < 20; i++) add(new Button("Button " + i)); } } FlowLayout ukladá komponenty zľava doprava, koľko sa ich do panelu vojde. V rámci toho sú Jednotlivé komponenty vycentrované. Súbor: FlowLayout1.java
BorderLayout import java.awt.*; import java.applet.*; publicclass BorderLayout1 extends Applet { publicvoid init() { int i = 0; setLayout(new BorderLayout()); add("North", new Button("Button " + i++)); add("South", new Button("Button " + i++)); add("East", new Button("Button " + i++)); add("West", new Button("Button " + i++)); add("Center", new Button("Button " + i++)); } } BorderLayout rozdelí panel na 5 častí, pomocou metódy add vkladáme podkomponenty do tohto panelu. Jednotlive časti sa adresujú BorderLayout.Center, BorderLayout.West, BorderLayout.East, BorderLayout.North, BorderLayout.South, resp. viď príklad. Súbor: BorderLayout1.java
GridLayout import java.awt.*; import java.applet.*; publicclass GridLayout1 extends Applet { publicvoid init() { setLayout(new GridLayout(7,3)); for(int i = 0; i < 20; i++) add(new Button("Button " + i)); } } GridLayout je pravideľná mriežka. Jednotlivé podkomponenty do nej vkladáme po riadkoch, pomocou metódy add(). CardLayout obsahuje nezávislé panely, ktoré vkladáme pomocou metódy add(). Na preklápanie medzi jednotlivými panelmi používame metódy first(), next(), last(). Súbor: GridLayout1.java
CardLayout class ButtonPanel extends Panel { ButtonPanel(String id) { setLayout(new BorderLayout()); add("Center", new Button(id)); } } publicclass CardLayout1 extends Applet { Button first = new Button("First"), second = new Button("Second"), third = new Button("Third"); Panel cards = new Panel(); CardLayout cl = new CardLayout(); publicvoid init() { setLayout(new BorderLayout()); Panel p = new Panel(); p.setLayout(new FlowLayout()); p.add(first); p.add(second); p.add(third); add("North", p); cards.setLayout(cl); cards.add("First", new ButtonPanel("first")); cards.add("Second", new ButtonPanel("second")); cards.add("Third", new ButtonPanel("third")); add("Center", cards); } } publicboolean action(Event evt, Object arg) { if (evt.target.equals(first)) cl.first(cards); elseif (evt.target.equals(second)) { cl.first(cards); cl.next(cards); } elseif (evt.target.equals(third)) cl.last(cards); else returnsuper.action(evt, arg); returntrue; } Súbor: CardLayout1.java
Spracovanie udalosti Jedným spôsobom, ako môžeme odchytávať udalosti, že predefinujem nasledujúce metódy: action (Event evt, Object what)stlačenie buttonu, check-box, vybratie položky z combo-boxu, ... keyDown (Event evt, int key)stlačenie klávesu, key predstavuje kód klávesu z evt.key, keyUp(Event evt, int key) - uvoľnenie klávesu, lostFocus(Event evt, Object what) - strata fokusu objeku, gotFocus(Event evt, Object what) - získanie fokusu, mouseDown(Event evt, int x, int y) - stlačenie myši na súradniciach x,y, mouseUp(Event evt, int x, int y) - pustenie myši na súradniciach x,y, mouseMove(Event evt, int x, int y) - presun myši, mouseDrag(Event evt, int x, int y) - dragovanie myši, od mouseDown po mouseUp, mouseEnter(Event evt, int x, int y) - myš vliezla do komponentu mouseExit(Event evt, int x, int y) - myš ušla z komponentu Iným spôsobom je technika Listenerov, bude neskôr...
Spracovanieudalostí public class AutoEvent extends Applet { Hashtable h = new Hashtable(); String[] event = { "keyDown", "keyUp", "lostFocus", "gotFocus", "mouseDown", "mouseUp", "mouseMove", "mouseDrag", "mouseEnter", "mouseExit“ }; MyCanvas b1 = new MyCanvas(this, Color.blue), b2 = new MyCanvas(this, Color.red); • Ilustrácia event-handlovacích rutín: keyDown, keyUp, lostFocus, gotFocus, mouseDown, mouseUp, mouseMove, mouseDrag, mouseEnter, mouseExit. • Hlavný applet rozdelí ako BorderLayout na 3častivľavo-west je modrý canvas, vpravo-east je červený canvas,stredný panel je rozdelený ako grid s 2 stĺpcami. public void init() { setLayout(new BorderLayout()); Panel p = new Panel(); add(p,BorderLayout.CENTER); p.setLayout(new GridLayout(event.length+1,2)); for(int i = 0; i < event.length; i++) { TextField t = new TextField(); t.setEditable(false); p.add(new Label(event[i], Label.CENTER)); p.add(t); h.put(event[i], t); } add(b1,BorderLayout.WEST); add(b2,BorderLayout.EAST); Súbor: AutoEvent.java
MyCanvas class MyCanvas extends Canvas { AutoEvent parent; Color color; public MyButton(AutoEvent parent, Color color) { this.parent = parent; this.color = color; } public boolean keyDown(Event evt, int key) { TextField t = (TextField)parent.h.get("keyDown"); t.setText(evt.toString()); return true; } . . . . . . . . . . . . . . • Do stĺpcov sú umiestnené labely v ľavom a textfieldy v pravom stĺpci. • Label popisuje event, ktorý sa vypisuje do textfieldu v pravo na tom istom riadku, so všetkými argumentami ktoré si možeme prečítať v handlovacej rutine. public void paint(Graphics g) { g.setColor(color); g.fill3DRect(0, 0, getWidth(), this.getHeight(), true); g.setColor(Color.black); g.draw3DRect(0, 0, getWidth(), this.getHeight(), true); } Súbor: MyCanvas.java
Listener model • druhým spôsobom je použitie rôznych alternácií Listenera, resp. Adaptera, • každý komponent, ktorý použijeme, generuje isté druhy udalostí, napr. Choice, tzv. combo-box, medzi inými ItemEvent, KeyEvent, ... • pre rôzne druhy udalostí máme adekvátne rôzne Listenery, napr. ItemListener, KeyListener, MouseListener, ... • XXXListerer je interface, ktorý predpisuje triede, aké VŠETKY metódy musí poskytovať, aby bola hodná titulu byť XXXListernerom, napr. mouseMoved( MouseEvent e), mouseDragged(MouseEvent e) pre MouseMotionListener, • hoc tieto metódy možu mať prázdne telá, musia byť definované ! • XXXAdapter je už existujúca trieda, ktorá už je XXXListenerom. XXXAdapter použijeme tak, že vytvoríme jeho podtriedu, a predefinujeme len tie metódy, ktorým chceme dať naše riadenie, ostatné majú defaultné správanie, v nasledujúcich príkladoch si ilustrujeme • Action/Key-Listerner a MouseMotionListener/Adapter ako alternatívu, • ukážeme si viacero spôsobov použitia, • z jazykového hľadiska uvidíme anonymnú a vnorenú triedu v jave.
Listener model • trieda Button2 • obsahuje dve • vnorené podtriedy • B1, B2, ktoré nie sú • v separátnych • súboroch. • 3 veci, ktoré musíme: • vytvoriť komponent, • pridať komponent, • priviazať listener/adapter import java.awt.*; import java.awt.event.*; import java.applet.*; public class Button2 extends Applet { Button b1 = new Button("Button 1"), b2 = new Button("Button 2"); public voidinit() { b1.addActionListener(new B1()); b2.addActionListener(new B2()); add(b1); add(b2); } classB1 implements ActionListener { // trieda vnorená do triedy public void actionPerformed(ActionEvent e) { getAppletContext().showStatus("Button 1"); } } classB2 implements ActionListener {// trieda vnorená do triedy public void actionPerformed(ActionEvent e) { getAppletContext().showStatus("Button 2"); } } } Súbor: Button2.java
Keď vám to nefunguje • skontrolujte si, či ste urobili všetky tri akcie: • komponent = new Komponent(), napr. b1 =new Button(“…”), ak nie, pravdpodobne vám každá ďalšia operácia s komponentom vygeneruje null-pointer exception, lebo neexistuje, • kamsi.add(komponent), napr. this.add(b1). ak nie, tak ho nevidíte. ak je neviditeľný, napr. Canvas, Panel, prefarbite ho na žlto, ak nevidíte žltú, máte problém... • komponent.addXXXListener(XXXListener), napr. b1.addActionListener(…) vidíte ho, ale vaša aplikácia sa vám „nehýbe“. Do Listenera, o ktorom ste presvedčení, že má odchytávať udalosti, vložte System.out.println(e). Ak sa nezačne nič písať na konzolu: • alebo ste zabudli priviazať listenera cez addXXXListener, • udalosť vám chytá iný listener, • komponent nemá focus, preto na udalosti nereaguje. • Tento návod nie je všeliek, na väčšinu úvodných chýb vám dúfam pomôže
Trieda vnorená do metódy syntaktická zmena oproti Button2 je, že actionListernery B1 a B2 sú vnorené do metódy init(), ktorá je v triede Button1 public class Button1 extends Applet { Button b1 = new Button("Button 1"), b2 = new Button("Button 2"); public voidinit() { classB1 implements ActionListener { // trieda B1 vnorená do metódy init public void actionPerformed(ActionEvent e) { getAppletContext().showStatus("Button 1"); } } b1.addActionListener(new B1()); classB2 implements ActionListener {// trieda B2 vnorená do metódy init public void actionPerformed(ActionEvent e) { getAppletContext().showStatus("Button 2"); } } b2.addActionListener(new B2()); add(b1); add(b2); } } Java nám vygeneruje: Button1.class Button1$B1.class Button1$B2.class Súbor: Button1.java
Anonymná metóda príklad Button1 je blízko, aby sme objavili myšlienku anonymnej podtriedy. B1 a B2 sú teraz nepomenované podtriedy. public class Button3 extends Applet { Button b1 = new Button("Button 1"), b2 = new Button("Button 2"); public class init() { b1.addActionListener(new ActionListener() { // anonymná trieda public void actionPerformed(ActionEvent e) { getAppletContext().showStatus("Button 1"); } }); b2.addKeyListener(new KeyAdapter() { // anonymná podtrieda KeyAdaptera public void keyPressed(KeyEvent e) { getAppletContext().showStatus("pressed: "+e.getKeyChar()); } }); add(b1); add(b2); } } Java nám vygeneruje: Button3.class Button3$1.class Button3$2.class Súbor: Button3.java
Od udalosti k listeneru • nasledujúca tabuľka ilustruje, ktorý komponent vie aké udalosti generovať, • ak chceme odchytávať XXXEvent generovaný komponentom, v ďalšej tabuľke si nájdeme XXXListerer (resp. XXXAdapter), ktorý túto udalosť vie spracovať, • druhá tabuľka nám hovorí, ktoré metódy • musíme(v XXXListerneri) definovať, resp. • možeme(v XXXAdapteri) predefinovať. Vysvetlivky: ActionEvent – špecifická akcia na komponente, napr. pre Button je to stlačenie pomocou myši, alebo klávesnicou (pomocou medzery, ak má focus), AdjustmentEvent – komponent sa scrolluje, ComponentEvent – komponent sa zmenil, presunul, zväčšil, zviditeľnil, ... ContainerEvent – zmena stavu kontaintera, pridal/zrušil sa pod-komponent, FocusEvent - komponent získal/stratil focus, ItemEvent - položka v Choice, List bola vybratá, zrušená, KeyEvent - akcia na klávesnici, stlačenie, pustenie klávesu, MouseEvent - akcia na myške, chytá MouseListerner, MouseMotionListener, MouseWheelEvent - kolečko myši, chytá MouseWheelListener, TextEvent - text v TextArea, resp. TextField sa zmenil, WindowEvent - okno zmenilo status, napr. bolo otvorené, zatvorené, minimalizované, zmenilo focus,
Udalosti komponentov Komponent Udalosť Adjustable AdjustmentEvent Applet ContainerEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent Button ActionEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent Canvas FocusEvent, KeyEvent, MouseEvent, ComponentEvent Checkbox ItemEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent CheckboxMenuItem ActionEvent, ItemEvent Choice ItemEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent Component FocusEvent, KeyEvent, MouseEvent, ComponentEvent Container ContainerEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent Dialog ContainerEvent, WindowEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent FileDialog ContainerEvent, WindowEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent Frame ContainerEvent, WindowEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent Label FocusEvent, KeyEvent, MouseEvent, ComponentEvent List ActionEvent,FocusEvent,KeyEvent, MouseEvent, ItemEvent, ComponentEvent Menu ActionEvent MenuItem ActionEvent Panel ContainerEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent PopupMenu ActionEvent Scrollbar AdjustmentEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent ScrollPane ContainerEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent TextArea TextEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent TextComponent TextEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent TextField ActionEvent, TextEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent Window ContainerEvent, WindowEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent
Seriál o myši • na ďalšej sérii elementárnych príkladov ukážeme rôzne spôsoby použitia MouseMotionListener/Adapter • okrem prvého príkladu v sérii - ten ilustruje starý spôsob, t.j. metódu mouseMove(Event evt, int x, int y), • odchytávame udalosť pohybu myšou, posledných 50 súradníc bodov si pamätáme v kolekcii Vector:Vector listOfPositions; // reprezentácia trajektórieposledných 50 bodov • v metóde paint ich prekreslujeme ako úsečky: public void paint( Graphics g ) { // kreslenie krivky z bodov trajektórie g.setColor( Color.white ); for (int j = 1; j<listOfPositions.size(); ++j ) { Point A =(Point)(listOfPositions.elementAt(j-1)); Point B = (Point)(listOfPositions.elementAt(j)); g.drawLine(A.x, A.y, B.x, B.y); } } • posledný príklad série Mouse ilustruje túto aplikáciu s KeyListenerom, t.j. “myš“ ovládame šípkami na klávesnici.
Myš po starom publicclass Mouse2 extends Applet { int width, height; Vector listOfPositions; // reprezentácia trajektórie // posledných 50 bodov publicvoid init() { width = getSize().width; height = getSize().height; setBackground(Color.black); listOfPositions = new Vector(); } // tu chytáme pohyb myšou na súr. x,y publicboolean mouseMove(Event evt, int x, int y) { if (listOfPositions.size()>=50)// ak je veľa // bodov,vyhodíme najstarší bod trajektórie listOfPositions.removeElementAt(0); // pridáme nový bod listOfPositions.addElement(new Point(x,y)); repaint();// prekreslíme applet returntrue;// udalosť sme spracovali } Pohyb myši odchýtávame boolean mouseMove() boolean mouseMove odchytí udalosť od myši, x,y sú súradnice, kde udalosť nastala, výsledná hodnota informuje či sme udalosť spracovali Súbor:Mouse2.java
Myš public class Mouse4 extends Applet { int width, height; Vector listOfPositions; // 50 posledných súradníc bodov myšky public void init() { width = getSize().width; height = getSize().height; setBackground( Color.black ); listOfPositions = new Vector(); addMouseMotionListener( new ML() ); } class ML implements MouseMotionListener { public void mouseMoved( MouseEvent e ) { if ( listOfPositions.size() >= 50 ) listOfPositions.removeElementAt( 0 ); listOfPositions.addElement(new Point( e.getX(), e.getY())); repaint(); } public void mouseDragged( MouseEvent e ) { } } vnorená trieda ML implementuje MouseMotionListener, teda musí definovať mouseMoved(e) aj mouseDragged(e), aj keď druhá z nich je prázdna. ML rovnako môžeme definovať v ML.java Súbor:Mouse4.java
Myš public class Mouse3 extends Applet implements MouseMotionListener { int width, height; Vector listOfPositions; // 50 posledných súradníc bodov myšky public void init() { width = getSize().width; height = getSize().height; setBackground( Color.black ); listOfPositions = new Vector(); addMouseMotionListener(this); } teraz samotná trieda Mouse3 implementuje MouseMotionListener, teda rovnako ako v predchádzajú-com príklade, definuje mouseMoved(e) aj mouseDragged(e). Rozdieľ je v tom, že MMListener teraz privesíme pomocou addMMListener(this), nie addMMListener(new …()). public voidmouseMoved( MouseEvent e ) { if ( listOfPositions.size() >= 50 ) listOfPositions.removeElementAt( 0 ); listOfPositions.addElement( new Point( e.getX(), e.getY() ) ); repaint(); } public voidmouseDragged(MouseEvent e ) { } Súbor:Mouse3.java
Myš public class Mouse5 extends Applet { int width, height; Vector listOfPositions; // 50 posledných súradníc bodov myšky public void init() { width = getSize().width; height = getSize().height; setBackground( Color.black ); listOfPositions = new Vector(); addMouseMotionListener( new MA() ); } // tu bolo implements MouseMotionListener class MA extends MouseMotionAdapter { public void mouseMoved( MouseEvent e ) { if ( listOfPositions.size() >= 50 ) listOfPositions.removeElementAt( 0 ); listOfPositions.addElement( new Point( e.getX(), e.getY() ) ); repaint(); } } // a tu bola public void mouseDragged( MouseEvent e ) { } } MA je teraz podtrieda MouseMotionAdapter, v ktorej predefinujeme len tie metódy, ktoré nás zaujímajú, t.j. mouseMoved(e) Súbor:Mouse5.java
Myš public class Mouse6 extends Applet { int width, height; Vector listOfPositions; // 50 posledných súradníc bodov myšky public void init() { width = getSize().width; height = getSize().height; setBackground( Color.black ); listOfPositions = new Vector(); addMouseMotionListener(new MouseMotionAdapter() { public void mouseMoved( MouseEvent e ) { if ( listOfPositions.size() >= 50 ) listOfPositions.removeElementAt( 0 ); listOfPositions.addElement( new Point( e.getX(), e.getY() ) ); repaint(); } } //class ); // add } vytvoríme anonymnú triedu pomocou MMAdaptera, resp. MMListenera – podľa zvolenej možnosti definujeme v nej jednu či dve metódy. Súbor:Mouse6.java
“Myš na schodoch” drobná variácia myši ovládanej pomocou šípiek na klávesnici public void init() { … addKeyListener(this); } publicvoid keyReleased(KeyEvent key) { } publicvoid keyTyped(KeyEvent key) { } publicvoid keyPressed(KeyEvent key) { switch (key.getKeyCode()) { case 37 :x-=10; break; case 38 :y-=10; break; case 39 :x+=10; break; case 40 :y+=10; break; } … } publicboolean keyDown(Event evt, int key) { switch (key) { case Event.RIGHT:x+=10; break; case Event.LEFT:x-=10; break; case Event.UP:y-=10; break; case Event.DOWN:y+=10; break; default: returnfalse; } . . . verzia pomocou KeyListenera verzia pomocou boolean keyDown Súbor:Mouse1.java Súbor:Mouse7.java
Cvičenie public class Patnast extends Applet { int a[][] = { {2,3,5,4}, // počiatočná konfigurácia {1,6,7,8}, {0,11,10,9}, {12,14,15,13} }; Button[] but = new Button[16]; public void init() { resize(300,300); setLayout(new GridLayout(4,4)); but[0] = new Button(""); for(int i = 1; i<16; i++) but[i] = new Button(""+i); for(int i = 0; i<4; i++) for(int j = 0; j<4; j++) add(but[a[i][j]]); } }