Predavanje br. index|1|2|3|4|5|6|7|8|9|10|11|12|13|14|HOME
Što su komponente? – labele – tri koraka u dodavanju
komponente – gdje je metoda paint()? – metode klase Label – buttoni – akcije na
buttonima – primjer appleta sa akcijom na buttonu – različiti obrasci za
događaje – višestruki ActionListeneri – metode za buttone – Action naredbe –
više buttona u istom appletu – unutarnje klase kao EventListeneri – tekstualna
polja – primjer tekstualnih polja u Javi – TextArea – klasa TextComponent –
sučelje TextListener i klasa TextEvent – klasa Canvas – klasa Choice – metode
klase Choice – klasa ItemListener – klasa Checkbox – događaji iz klase Checkbox
– klasa CheckboxGroup – primjer CheckboxGroup – klasa List – metode klase List –
događaji klase List – klasa Scrollbar
Komponente su sastavnice grafičkog korisničkog sučelja (GUI, graphical user interface).
U Javi, komponente su podklase od java.awt.Component,
a najčešće korištene su:
Canvas
TextField
TextArea
Label
List
Button
Choice
Checkbox
Frame
JButton
JLabel
JComboBox
JMenu
Sve komponente se iscrtavaju samostalno (bez pisanja posebne paint() metode.
Najjednostavnija komponenta je java.awt.Label.
U sljedećem primjeru je Label l redak
teksta koji je read-only.
import java.applet.*; import java.awt.*; public class HelloContainer extends Applet { public void init() { Label l; l = new Label("Hello Container"); this.add(l); } }
<APPLET
CODE="HelloContainer.class"
CODEBASE="http://student.math.hr/~vedris/java/classes"
WIDTH=100
HEIGHT=100>
</APPLET>
Kao
i obično, program započinjete importiranjem potrebnih klasa. U ovom slučaju to
su java.applet.Applet
i java.awt.Label.
Naša
klasa će imati samo jednu metodu, init(). Ona će
obaviti tri stvari. Deklarirat će da je l labela,
instancirati je pomoću konstruktora Label(String
s) i dodati je razmještaju (layout). Općenito, to se ne
mora obaviti uvijek unutar metode init(), ali
najčešća praksa je upravo takva.
public void init() { Label l; l = new Label("Hello Container"); this.add(l); }
Ključna stvar koju valja zapamtiti o dodavanju komponenti appletu su sljedeća tri koraka:
Prva dva koraka moraju se obaviti prilikom kreiranja instance bilo koje klase, tako da nam samo treći korak predstavlja novost.
Možete to napraviti, naravno, i u jednoj naredbi, na primjer ovako:
this.add(new Label("Hello
Container"));
Nedostatak ovog kraćeg zapisa je taj što se izgubila referenca na labelu (varijabla l). Ipak, labele se u pravilu ne mijenjaju, tako da uglavnom nije posebna smetnja.
paint()Primijetite
da u našem appletu nema paint(), a
tekst se svejedno ispisuje na ekranu. Komponente se, naime, same iscrtavaju.
Svaki put kad se container kao što je applet ponovno iscrta, on pozove ne
samo svoju vlastitu paint()
metodu, nego i paint() metode
svih svojih komponenti. Klasa java.awt.Label
ima svoju vlastitu paint() metodu
koja zna kako se treba iscrtati. O iscrtavanju komponenti ne morate voditi
računa dok god ne kreirate vlastite klase komponenata ili izmijenite izgled
sistemskih komponenata.
Labele
su jednostavni objekti koji imaju tek nekoliko konstruktora i vlastitih, ako se
izuzmu one koje su naslijeđene od java.awt.Component
(kojoj je java.awt.Label
podklasa).
public final static int LEFT public final static int CENTER public final static int RIGHT public Label() public Label(String text) public Label(String text, int alignment) public void addNotify() public int getAlignment() public synchronized void setAlignment(int alignment) public String getText() public synchronized void setText(String text)
Već
smo vidjeli osnovni konstruktor za labele. Možete također kreirati labelu
koristeći konstruktor Label() bez
argumenata, no to općenito nema smisla. Nadalje, možete odrediti da tekst bude
poravnat lijevo, desno ili centrirano, za što vam stoji na raspolaganju
odgovarajući konstruktor:
Label center = new Label("Ova labela je centrirana", Label.CENTER);Label left = new Label("Ova labela je lijevo poravnata", Label.LEFT);Label right = new Label("Ova labela je desno poravnata", Label.RIGHT);
Dvije
su metode iz java.awt.Label
koje će povremeno biti potrebne, a to su getText() i
setText(String
s). One dozvoljavaju da doznate i promijenite tekst labele dok se
applet izvršava. Na primjer,
String s = l.getText();l.setText("Ovo je nova labela");
Buttoni
su instance klase java.awt.Button
koja je podklasa od java.awt.Component.
Buttoni se kreiraju pomoću konstruktora Button(String
label). On će kreirati novi button sa labelom koja će na njemu
biti ispisana. Kad ga kreirate, možete ga dodati razmještaju. Na primjer,
Button b; b = new Button("My First Button"); this.add(b);
Sintaksa je gotovo identična kao za labele i vidjet ćete da je takva i za ostale komponente grafičkog sučelja. Jedino što se mijenja su konstruktori.
Kraći oblik je također isti:
add(new Button("My First
Button"));
Evo jednog appleta koji sadrži button:
import java.applet.*;import java.awt.*; public class FirstButton extends Applet { public void init () { this.add(new Button("Moj prvi Button")); } }<APPLET
CODE="HelloContainer.class"
CODEBASE="http://student.math.hr/~vedris/java/classes"
WIDTH=100
HEIGHT=100>
</APPLET>
Za
razliku od labela, buttoni čine nešto kad kliknete na njih. Kad miš klikne na
neki objekt tipa Button, onda
će on ispaliti objekt tipa ActionEvent.
Da biste bili spremni odgovoriti na taj događaj, potrebno je buttonu pridružiti
i odgovarajući ActionListener. Na primjer,
Button beep = new Button("Beep"); add(beep); // dodajemo buttom razmjestaju beep.addActionListener(myActionListener); // pridruzujemo buttonu action listener
Ovdje
je myActionListener
referenca na objekt koji implementira sučelje (interface) java.awt.event.ActionListener.
To sučelje propisuje samo jednu metodu:
public abstract void
actionPerformed(ActionEvent e)
Objekt
tipa ActionListener
učinit će nešto s rezultatom, objektom tipa ActionEvent
kojeg je ispalio button nakon što je zabilježio klik mišem. Na primjer, sljedeća
klasa će, kad dobije ActionEvent,
proizvesti beep signal:
import java.awt.*;import java.awt.event.*; public class BeepAction implements ActionListener { public void actionPerformed(ActionEvent e) { Toolkit.getDefaultToolkit().beep(); } }
Sljedeći
applet ima button označen labelom na kojoj piše "Beep". Button je na uobičajeni
način dodan razmještaju, a metoda addActionListener()
propisuje da će na buttonove ActionEvente reagirati odgovarajući
ActionListener, u ovom slučaju objekt klase BeepAction.
import java.applet.*;import java.awt.*;import java.awt.event.*; public class BeepApplet extends Applet { public void init () { // Konstruiramo button Button beep = new Button("Beep"); // dodajemo button razmjestaju this.add(beep); // propisujemo da ce action evente koje ovaj button posalje // obraditi novi objekt klase BeepAction beep.addActionListener(new BeepAction()); } }
<APPLET
CODE="BeepApplet.class"
CODEBASE="http://student.math.hr/~vedris/java/classes"
ARCHIVE="Beep.jar"
WIDTH=100
HEIGHT=100>
</APPLET>
Glavna
je prednost Javinog modela događaja je da se GUI može odvojiti od ostalog koda.
Kako je ActionListener
sučelje (interface), a ne klasa, on može biti implementiran gdje god nam
odgovara. Na primjer, applet može i sam obrađivati svoje događaje, što ćemo
vidjeti iz sljedećeg primjera:
import java.applet.*;import java.awt.*;import java.awt.event.*; public class BeepApplet extends Appletimplements ActionListener {
public void init () { // Construct the button Button beep = new Button("Beep"); // add the button to the layout this.add(beep); // specify that action events sent by this // button should be handled by the applet itself beep.addActionListener(this); } public void actionPerformed(ActionEvent e) { Toolkit.getDefaultToolkit().beep(); } }
<APPLET
CODE="BeepApplet.class"
CODEBASE="http://student.math.hr/~vedris/java/classes"
WIDTH=100
HEIGHT=100>
</APPLET>
Primijetite da niste ograničeni na samo jedan listener po događaju. Na primjer, sljedeći program generira pet beep-ova svaki put kad pritisnete button.
import java.applet.*;import java.awt.*;import java.awt.event.*; public class BeepFiveApplet extends Applet { public void init () { // Construct the button Button beep = new Button("Beep"); // add the button to the layout this.add(beep); // specify that action events sent by this // button should be handled by a new BeepAction object beep.addActionListener(new BeepAction()); beep.addActionListener(new BeepAction()); beep.addActionListener(new BeepAction()); beep.addActionListener(new BeepAction()); beep.addActionListener(new BeepAction()); } }
<APPLET
CODE="BeepFiveApplet.class"
CODEBASE="http://student.math.hr/~vedris/java/classes"
ARCHIVE="BeepFive.jar"
WIDTH=100
HEIGHT=100>
</APPLET>
Kad
pritisnete button, on će lansirati ActionEvent, a
svaki od pet objekata klase BeepAction
dobit će kopiju tog događaja. Redosljed primanja tih kopija nije
specificiran.
Ako je vaše računalo prebrzo da biste čuli svih pet beep-ova, dodajte unutar metode ActionPerformed() iz klase BeepAction još i naredbu
System.out.println("Beep");
Pogledate li applet pomoću appletviewera, moći ćete pratiti ispis svaki put kad pritisnete button i vidjeti da se akcija zaista događa pet puta.
Buttoni
su jednostavni objekti. Uglavnom sve što trebate napraviti s njima je dodati ih
u razmještaj i pridružiti im ActionListener.
Na raspolaganju su vam i sljedeće metode:
public void addNotify()public String getLabel()public synchronized void setLabel(String label)public void setActionCommand(String command)public String getActionCommand()public void addActionListener(ActionListener l)public void removeActionListener(ActionListener l)
addNotify()
kreira takozvani peer objekt
za zadani button, tj. native masku koja izgleda kao Windows button ili
Mac button ili Motif button, no ona se rijetko direktno poziva.
Metode
getLabel() i
setLabel(String
s) omogućuju dohvaćanje i mijenjanje teksta koji se pojavljuje na
buttonu za vrijeme izvršavanja appleta. Na primjer, za neki Button b,
možemo imati:
String s = b.getLabel();b.setLabel("Here's the new label");
Primijetite
da metoda unatoč sugestivnom imenu getLabel()
vraća objekt tipa String, a ne
Label.
Metode
setActionCommand()
i getActionCommand()
modificiraju komandni string koji sa sobom nosi ActionEvent.
Po pretpostavci to je labela buttona, ali to se može promijeniti. Na primjer,
možete zadati broj ponvljanja beep signala koji će applet proizvesti na klik
mišem (pogledajte BeepFiveApplet).
Metoda
addActionListener()
registrira neki objekt kao onaj koji bi trebao primiti ActionEvent
koji će Button
ispaliti. Metoda removeActionListener()
poništava tu registraciju, tako da objekt tipa ActionListener
više neće primati ActionEvente koje button ispali.
Metode
setActionCommand()
i getActionCommand()
modificiraju komandni string koji putuje uz ActionEvent.
Po pretpostavci, to je labela buttona, ali to se može promijeniti. Na primjer,
možete na taj način proslijediti broj ponaljanja beep signala koje applet treba
proizvesti.
import java.applet.*;import java.awt.*;import java.awt.event.*; public class BeepFiveApplet extends Applet { public void init () { // Construct the button Button beep = new Button("Beep"); // add the button to the layout this.add(beep); // specify that action events sent by this // button should be handled by the applet itself beep.addActionListener(new MultiBeepAction()); beep.setActionCommand("5"); } } class MultiBeepAction implements ActionListener { public void actionPerformed(ActionEvent ae) { int n; try { n = Integer.parseInt(ae.getActionCommand()); } catch (NumberFormatException e) { n = 1; } Toolkit tk = Toolkit.getDefaultToolkit(); for (int i = 0; i < n; i++) tk.beep(); } }
<APPLET
CODE="BeepFiveApplet.class"
CODEBASE="http://student.math.hr/~vedris/java/classes"
ARCHIVE="MultiBeep.jar"
WIDTH=200
HEIGHT=200>
</APPLET>
Naravno,
moguće je imati više od jednog buttona u appletu. Svaki button koji će izazvati
neku akciju mora registrirati bar jedan objekt koji je ActionListener.
Različiti buttoni mogu registrirati različite ActionListenere
, ali ih mogu i dijeliti. ActionListeneri
za buttone mogu pripadati istoj klasi, ali ne moraju. Ako dva buttona
registriraju isti ActionListener,
uobičajeno je koristiti action komandu da bismo razlikovali akcije.
import java.applet.*;import java.awt.*;import java.awt.event.*; public class TwoButtons extends Applet { public void init() { MultiBeepAction mba = new MultiBeepAction(); // Construct the button Button beep = new Button("Beep Once"); // add the button to the layout this.add(beep); beep.addActionListener(mba); beep.setActionCommand("1"); Button beepTwice = new Button("Beep Twice"); beepTwice.addActionListener(mba); beepTwice.setActionCommand("2"); this.add(beepTwice); } } class MultiBeepAction implements ActionListener { public void actionPerformed(ActionEvent ae) { int n; try { n = Integer.parseInt(ae.getActionCommand()); } catch (NumberFormatException e) { n = 1; } Toolkit tk = Toolkit.getDefaultToolkit(); for (int i = 0; i < n; i++) tk.beep(); } }
<APPLET
CODE="TwoButtons.class"
CODEBASE="http://student.math.hr/~vedris/java/classes"
ARCHIVE="TwoButtons.jar"
WIDTH=200
HEIGHT=100>
</APPLET>
Uobičajeno
je da klasa koja realizira event listener bude unutarnja klasa. To se
najčešće primjenjuje na prilagođene podklase komponenata koje žele same
obrađivati svoje događaje.
import java.applet.*;import java.awt.*;import java.awt.event.*; public class TwoButtons extends Applet { public void init() { MultiBeepAction mba = new MultiBeepAction(); // Construct the button Button beep = new Button("Beep Once"); // add the button to the layout this.add(beep); // specify that action events sent by this // button should be handled by the MultiBeepAction mba beep.addActionListener(mba); beep.setActionCommand("1"); Button beepTwice = new Button("Beep Twice"); beepTwice.addActionListener(mba); beepTwice.setActionCommand("2"); this.add(beepTwice); } class MultiBeepAction implements ActionListener { public void actionPerformed(ActionEvent ae) { int n; try { n = Integer.parseInt(ae.getActionCommand()); } catch (NumberFormatException e) { n = 1; } Toolkit tk = Toolkit.getDefaultToolkit(); for (int i = 0; i < n; i++) tk.beep(); } }}
<APPLET
CODE="TwoButtons.class"
CODEBASE="http://student.math.hr/~vedris/java/classes"
ARCHIVE="TwoButtonsIC.jar"
WIDTH=200
HEIGHT=100>
</APPLET>
Klasa
java.awt.TextField
omogućuje ugradnju maske za unos i editiranje jedne linije teksta. Korisna je za
jednostavne operacije unosa malih količina podataka. Ima četiri
konstruktora:
public TextField() public TextField(String text) public TextField(int num_chars) public TextField(String text, int num_chars)
Zbog
načina na koji Java razmješta tekst, konstruktor bez argumenata bi valjalo
izbjegavati. Koristite ili onaj koji ima String ili
zadajte broj znakova koje će ta kućica sadržavati. Na primjer,
TextField name = new TextField("Type your name here");TextField socialSecurity = new TextField(11);
Kad
korisnik pritisne tipku return ili enter unutar TextFielda,
ispali se jedan ActionEvent.
Možete ga uloviti pomoću ActionListenera,
isto kao u slučaju buttona. Imajte na umu da većina korisnika nije svjesna da se
nešto događa tek onda kad pritisnu return unutar TextFielda.
Zato uvijek osigurajte i alternativni način ispaljivanja ActionEventa,
na primjer pomoću buttona ili retka na izborniku.
Metoda
getText()
vraća sadržaj TextFielda.
Metoda setText(String
s) ga mijenja.
Metoda
setEditable()
omogućuje da korisniku dozvolite ili zabranite modificiranje sadržaja
TextFielda.
Sljedeći
applet čita tekst iz jednog TextFielda i
ispisuje ga velikim slovima u drugi TextField.
import java.applet.*;import java.awt.*;import java.awt.event.*; public class CapitalizeApplet extends Applet { private TextField input; private TextField output; public void init () { // Konstruiramo tekstualna polja this.input = new TextField(40); this.output = new TextField(40); this.output.setEditable(false); Button b = new Button("Capitalize"); // dodajemo komponente u razmjestaj this.add(input); this.add(b); this.add(output); // odredjujemo da action evente koje salju // button ili input TextField budu obradjeni od // istog objekta tipa CapitalizerAction CapitalizerAction ca = new CapitalizerAction(input, output); b.addActionListener(ca); this.input.addActionListener(ca); // ActionEvents koje salje polje output se ignoriraju. } } class CapitalizerAction implements ActionListener { TextField in; TextField out; public CapitalizerAction(TextField in, TextField out) { this.in = in; this.out = out; } public void actionPerformed(ActionEvent ae) { String s = in.getText(); out.setText(s.toUpperCase()); } }
<APPLET
CODE="CapitalizeApplet.class"
CODEBASE="http://student.math.hr/~vedris/java/classes"
ARCHIVE="Capitalize.jar"
WIDTH=500
HEIGHT=100>
</APPLET>
U
ovom programu korišten je drugačiji obrazac za obradu događaja. Konstruktor
klase CapitalizerAction
je iskorišten za prosljeđivanje referenci različitim komponentama koje metoda
actionPerformed()
modificira.
Klasa
java.awt.TextArea
je podklasa od java.awt.TextComponent
koja osigurava masku za editiranje više linija teksta. Korisna je za input i
output.

Na raspolaganju su nam četiri konstruktora:
public TextArea() public TextArea(String text) public TextArea(int rows, int columns) public TextArea(String text, int rows, int columns) public TextArea(String text, int rows, int columns, int scrollbars)
Zbog
načina na koji Java raspoređuje komponente, izbjegavajte korištenje konstruktora
bez argumenata. Radije počnite sa onim koji zadaje String ili
broj redaka i stupaca koje će ta površina zauzeti. Na primjer,
TextArea address = new TextArea("Upišite svoju adresu", 5, 80);
Po pretpostavci, TextAreas nema scrollbar. Možete ih dodati ako odgovarajućem konstruktoru prenesete neku od ovih konstanti:
TextArea.SCROLLBARS_BOTH TextArea.SCROLLBARS_HORIZONTAL_ONLY TextArea.SCROLLBARS_NONE TextArea.SCROLLBARS_VERTICAL_ONLY
Na primjer,
TextArea instructions = new TextArea("", 15, 70,TextArea.SCROLLBARS_VERTICAL_ONLY);
Za
razliku od TextFielda,
TextArea ne
generira nikakav actionEvent kad korisnik pritisne return unutar polja.
Umjesto toga, linija se prekida, a kursor prenosi u novi red.
No
i nadalje, metoda getText()
vraća tekst koji sadrži TextArea, a
setText() ga
mijenja. Metoda setEditable()
dopušta vam da odredite da li će korisnik moći mijenjati sadržaj. Obje klase,
TextField i
TextArea,
nasljeđuju sve ove metode od svoje nadklase, TextComponent.
Nadalje,
tekst možete dodavati na kraj pomoću metode append(),
umetati pomoću metode insert(), a
zamijeniti pomoću metode replaceRange():
public synchronized void insert(String text, int position)public synchronized void append(String text) public synchronized void replaceRange(String text, int start, int end)
I
TextArea i
TextField su
podklase od java.awt.TextComponent.
Ova klasa sadrži metode koje su zajedničke za obje klase, uključujući i nekoliko
metoda koje smo već vidjeli.: getText(),
setText(), i
setEditable().
Klasa TextComponent
ima također i metode za manipuliranje selekcijom i kursorom te za procesiranje
TextEventa.
Selekcija
se koristi za copy/paste ali i za druge svrhe. Prvi znak u TextComponenti
je znak broj 0; drugi je znak broj 1 i tako dalje.
public synchronized int getSelectionStart() public synchronized void setSelectionStart(int selectionStart) public synchronized int getSelectionEnd() public synchronized void setSelectionEnd(int selectionEnd) public synchronized void select(int selectionStart, int selectionEnd) public synchronized void selectAll() public synchronized String getSelectedText()
Kursor (caret) je mjesto insertiranja teksta. Tamo se pojavljuje tekst kad ga korisnik utipka. Dvije su metode koje to reguliraju:
public void setCaretPosition(int position) public int getCaretPosition()
Klase
TextArea i
TextField mogu
instalirati sučelje java.awt.event.TextListener
koje hvata događaje iz klase java.awt.event.TextEvent.
TextComponente
ispaljuju TextEvente
svaki put kad se njihov tekst promijeni. To se događa uglavnom svaki put kad
korisnik pritisne tipku unutar komponente.
Sučelje
TextListener
propisuje samo jednu metodu, textValueChanged():
public abstract void textValueChanged(TextEvent te)
Nekoj
TextComponenti
pridružujete TextListener
tako da pozovete njenu metodu addTextListener().
Na primjer,
TextArea password = new TextArea(24)password.addTextListener(new PasswordChecker());
Ipak, u najvećem broju slučajeva bit će posve dovoljno pročitati i postaviti tekst (get i set). Procesiranje znak po znak je relativno rijetko potrebno.
Napomenimo
da se TextListener
uklanja pozivanjem metode
removeTextListener().
public void removeTextListener(TextListener tl)
Klasa
java.awt.Canvas
definira pravokutnu površinu (podlogu, pozadinu) po kojoj možete pisati i crtati
koristeći metode iz klase java.awt.Graphics.
Klasa Canvas ima
samo tri metode:
public Canvas() public void addNotify() public void paint(Graphics g)
Podloge
uglavnom ne instancirate direktno. Umjesto toga pišete podklasu koja će
pregaziti paint() metodu
kako biste nacrta li sliku koju trebate. Na primjer, sljedeća podklasa od
Canvas crta
veliku crvenu elipsu koju možete dodati vašem appletu:
import java.awt.*; public class RedOval extends Canvas { public void paint(Graphics g) { Dimension d = this.getSize(); g.setColor(Color.red); g.fillOval(0, 0, d.width, d.height); } public Dimension getMinimumSize() { return new Dimension(50, 100); } public Dimension getPreferredSize() { return new Dimension(150, 300); } public Dimension getMaximumSize() { return new Dimension(200, 400); } }
Applet
koji koristi komponente nikako ne bi smio pregaziti metodu paint() jer će
to zbog načina na koji Java raspoređuje
komponente izazvati nepredvidljive rezultate. Umjesto toga treba kreirati
objekt tipa Canvas i sva
crtanja obaviti pomoću njegove paint()
metode.
Podloge se dodaju apletima na isti način kao i ostale komponente. Na primjer,
public void init() { this.add(new RedOval()); }
Podloge u pravilu ne ispaljuju nikakve događaje, no poslije ćete naučiti kako se to može promijeniti.
Klasa
java.awt.Choice
implementira popup izbornik sa fiksnom pozicijom (postoji također i klasa
java.awt.PopupMenu
kod koje pozicija nije fiksna i pojavljuje se kad korisnik klikne i drži desnu
tipku miša).