Ručno pozicioniranje komponenti
AWT je konstruisan tako da GUI programa može da funkcioniše podjedanko
dobro na različitim platformama i sa različitim rezolucijama ekrana, fontovima,
veličinama ekrana i slično,...Oslanjanje na koordinate u pikselima ima
za posledicu da program izgleda onako kako ste želeli na jednoj platformi,
dok na drugim platformama može biti neupotrebljiv usled preklapanja komponenti,...
Menadžeri postavke rade dinamičko smeštanje komponenti na ekranu i tako
zaobilaze te probleme.
Narvno, komponente je moguće postaviti na tačno određenu poziciju na
ekranu, koristeći koordinate u pikselima, u odnosu na apletov panel. To,
međutim, ima više nedostataka:
Sve instance Vašeg appleta neće imati panel jednake veličine. Veličinu
možete kontrolisati samo ako će se aplet pojavljivati jedino na vašim web
stranicama. Korisnici mogu menjati veličinu slobodnim prozorima u
hodu. Ako koristite layout manager, sve će komponente biti automatski prilagođene
novoj veličini prozora. Bez toga vrlo je teško postići takvo ponašanje.
Komponente će na različitim platformama zauzimati različite količine
prostora. Ručno pozicioniranje će imati smisla u aplikacijama koje su namenjene
izvršavanju na jednoj određenoj platformi. Apleti nisu pogodni za to.
Ručno pozicioniranje komponenti traži mnogo posla, pogotovo ako nemate
na raspolaganju neki alat koji će automatizirati taj proces.
Razmeštaj GridBagLayout u kombinaciji sa ugnježdenim panelima dovoljan
je za sve efekte koje biste inače mogli postići ručnim pozicioniranjem.
Ako ipak želite ručno pozicionirati komponente, onda prvo opozovite
layout manager naredbom:
setLayout(null);
Nakon toga zadajte poziciju i veličinu za svaku komponentu unutar paint()
metode (eksplicitno je rečeno da se to inače ne radi!), tako da pozovete
metode setLocation() and setSize():
public void setLocation(int x, int y)
public void setSize(int width, int height)
Ovde su x i y koordinate levog gornjeg ugla kutije koja omeđuje
komponentu, a width i height su njena širina i visina u pikselima.
Sledeći aplet staviće dugme veličine 30 x 40 piksela (tj. njegov levi gornji ugao) u tačku (25, 50):
import java.applet.*;
import java.awt.*;
public class RucniRazmestaj extends Applet {
private boolean postavljen = false;
private Button Dugme;
public void init() {
this.setLayout(null);
this.Dugme = new Button("OK");
this.add(this.Dugme);
}
public void paint(Graphics g) {
if (!this.postavljen) {
this.Dugme.setLocation(25, 50);
this.Dugme.setSize(30, 40);
this.postavljen = true;
}
}
}
<APPLET CODE="RucniRazmestaj.class" WIDTH=100 HEIGHT=100>
</APPLET>
Interface java.awt.LayoutManager implementiran je u više različitih
klasa, kao što su:
java.awt.FlowLayout
java.awt.BorderLayout
java.awt.CardLayout
java.awt.GridLayout
java.awt.GridBagLayout
Appleti ili kontejneri mogu koristiti ove i druge layout managere da
bi odlučili gde će postaviti komponente koje u njih programer dodaje.
Klasa java.awt.FlowLayout raspoređuje komponente s leva na desno dok ima prostora, a tada nastavlja na isti način odozgo na dole. Svaka komponenta u FlowLayout razmeštaju dobija upravo onoliko prostora koliko joj minimalno treba i ništa više. Takav je razmeštaj koristan za raspoređivanje GUI dugmića, ali za mnoge druge stvari nije. On je pretpostavljeni (default) razmeštaj za aplete i panele (posebne kontejnere).
Klasa java.awt.BorderLayout organizuje aplet u sekcije prema stranama sveta: North, South, East, West i Center. North, South, East i West su pravougaonici na rubovima apleta. Oni se kontinuirano šire prema veličini komponenata u njima. Center je ono što preostane u središtu.
Klasa java.awt.CardLayout deli aplet na površine u obliku karti gde svaka ima sopstveni razmeštaj. U svakom trenutku samo se jedna karta pojavljuje na ekranu. Korisnik može prebacivati izgled ekrana s jedne na drugu kartu, a svaka prikazuje različite skupove komponenti. Obično se to upoređuje sa HyperCardom na Macu ili Toolbookom na Windowsima. U Javi se to može koristiti kao serija maski za unos podataka ako sva polja ne mogu stati na ekran.
Klasa java.awt.GridLayout deli aplet na određeni broj redova i kolona te tako formira mrežu ćelija kao matricu. Kako se koja komponenta dodaje, ona se smešta u sledeću slobodnu ćeliju, počevši od levog ugla prema desno i prema dole. Svaka komponenta se podešava po veličini tako da pristaje u ćeliju. Takav razmeštaj će neke komponente nepotrebno stisnuti, a neke razvući, ali je veoma pogodan za razmeštanje panela.
Klasa java.awt.GridBagLayout daje najprecizniji od svih AWT razmeštaja. Razmeštaj je kao i GridLayout, ali komponente ne moraju biti iste veličine. Svaka komponenta može zauzeti jednu ili više ćelija. Štaviše, komponente nisu nužno smeštene u ćelije počevši od gornjeg levog ugla niti se moraju dodavati prema desno i prema dole.
U jednostavnim apletima sa samo nekoliko komponenti biće dovoljan jedan
razmeštaj. U komplikovanijima, međutim, često se aplet deli na panele koji
se raspoređuju prema nekom razmeštaju, a onda svaki panel snabdeti sopstvenim
layout managerom za raspoređivanje komponenti unutar njega.
FlowLayout je pretpostavljeni (default) razmeštaj za java.awt.Panel koji je nadklasa od java.applet.Applet, te se ne mora učiniti ništa posebno kako bi se FlowLayout kreirao unutar apleta. Međutim, ako ga želite koristiti unutar prozora, java.awt.Window, biće potrebni odgovarajući konstruktori.
Razmeštaji imaju konstruktore kao i ostale klase. Jedan od konstruktora za FlowLayout je:
public FlowLayout()
Dakle, za kreiranje novog objekta tipa FlowLayout piše se:
FlowLayout fl;
fl = new FlowLayout();
Kao i obično, to se može kompaktnije zapisati:
FlowLayout fl = new FlowLayout();
Apletu ćete reći koju specifičnu instancu klase LayoutManager želite koristiti, tako da taj objekt navedete u apletovoj metodi setLayout(). Ovu metodu klasa java.applet.Applet nasleđuje, kao i mnoge druge, iz klase java.awt.Container.
this.setLayout(fl);
Metoda setLayout() se uglavnom poziva u init() metodi. Uobičajeno je kreirati primerak razmeštaja direktno unutar poziva metode setLayout() ovako:
this.setLayout(new FlowLayout());
Poravnanje za neki FlowLayout se zadaje pomoću odgovarajućeg konstruktora.
Komponente su u apletu po pretpostavci centrirane, a mogu da budu i levo
ili desno pozicionirane, jer postoje konstante FlowLayout.LEFT, FlowLayout.RIGHT
ili FlowLayout.CENTER koje se navode prilikom pozivanja konstruktora, npr.
this.setLayout(new FlowLayout(FlowLayout.LEFT));
this.setLayout(new FlowLayout(FlowLayout.RIGHT));
this.setLayout(new FlowLayout(FlowLayout.CENTER));
Primer u kojem se poravnanje zadaje pomoću parametra oznake <APPLET>.
import java.applet.Applet;
import java.awt.Button;
import java.awt.FlowLayout;
public class TapeDeckAlign extends Applet {
public void init() {
FlowLayout f;
String align = getParameter("align");
if (align == null) f = new FlowLayout(FlowLayout.CENTER);
else if (align.equalsIgnoreCase("left"))
f = new FlowLayout(FlowLayout.LEFT);
else if (align.equalsIgnoreCase("right"))
f = new FlowLayout(FlowLayout.RIGHT);
else f = new FlowLayout(FlowLayout.CENTER);
setLayout(f);
add( new Button("Play"));
add( new Button("Rewind"));
add( new Button("Fast Forward"));
add( new Button("Pause"));
add( new Button("Stop"));
}
}
<APPLET CODE="TapeDeckAlign.class" WIDTH=200 HEIGHT=100><param
name="align" value="left"></APPLET>
S parametrom value="center", odnosno value="right" dobili bismo
centrirani i desno pozicionirani razmeštaj.
Većina LayoutManagera omogućuje kontrolu nad minimalnim vertikalnim
i horizontalnim prostorom koji razdvaja komponente. Za FlowLayout zadaje
se željeni prostor u pikselima, putem odgovarajućih argumenata u konstruktoru:
public FlowLayout(int alignment, int hspace, int vspace);
Na primer, da biste napravili FlowLayout sa deset piksela horizontalnog
i dvadeset piksela vertikalnog razmaka, sa levim poravnanjem, koristili
biste sledeći konstruktor:
FlowLayout fl = new FlowLayout(FlowLayout.LEFT, 20, 10);
Primer apleta koji tako raspoređuje buttone nalik onima za VCR:
import java.applet.*;
import java.awt.*;
public class SpaceTapeDeck extends Applet {
public void init() {
this.setLayout( new FlowLayout(FlowLayout.LEFT,
20, 10));
this.add( new Button("Play"));
this.add( new Button("Rewind"));
this.add( new Button("Fast Forward"));
this.add( new Button("Pause"));
this.add( new Button("Stop"));
}
}
<APPLET CODE="VCR2.class" WIDTH=200 HEIGHT=200> </APPLET>
this.setLayout(new BorderLayout());
U ovom tipu razmeštaja nema centriranja ni levog ili desnog poravnavanja, no možete dodati horizontalne i vertikalne razmake među komponentama. Na primer, za horizontalni razmak od 5 piksela i vertikalni od 10 piksela, stavili bismo:
this.setLayout(new BorderLayout(5, 10));
Kad želite dodati komponentu na određenu stranu, možete to učiniti na
primer ovako:
this.add(new Button("Start"), BorderLayout.SOUTH);
Kao što se iz sledećeg primera može videti, severna i južna sekcija
protežu se preko apleta s leva na desno. Istočna i zapadna se protežu od
dna severne do vrha južne sekcije. Ove četiri komponente biće velike onoliko
koliko je potrebno da bi u njih stale komponente koje im dodeljujete. Ono
što ostane, biće za centralnu sekciju. Tačne veličine su nepredvidljive.
Kao i tačan način pakiranja komponenti unutar sekcija.
import java.awt.*;
public class BorderLayout1 extends java.applet.Applet {
BorderLayout b = new BorderLayout();
Button north = new Button("North");
Button south = new Button("South");
Button east = new Button("East");
Button west = new Button("West");
Button center = new Button("Center");
public void init() {
setLayout(b);
add("North", north);
add("South", south);
add("East", east);
add("West", west);
add("Center", center);
}
}
<APPLET CODE="BorderLayout1.class" WIDTH=200 HEIGHT=100> </APPLET>
import java.applet.*;
import java.awt.*;
public class BorderLayout2 extends Applet {
public void init() {
this.setLayout(new
BorderLayout(20, 10));
this.add(new
Button("North"), BorderLayout.NORTH);
this.add(new
Button("South"), BorderLayout.SOUTH);
this.add(new
Button("East"), BorderLayout.EAST);
this.add(new
Button("West"), BorderLayout.WEST);
this.add(new Button("Center"),
BorderLayout.CENTER);
}
}
<APPLET CODE="BorderLayout2.class" WIDTH=200 HEIGHT=100> </APPLET>
Razmeštaj koji implementira klasa java.awt.CardLayout pretvara aplet u snop karata, od kojih svaka potencijalno ima svoj LayoutManager. U svakom trenutku na ekranu je vidljiva samo jedna karta. Možete prelaziti s jedne karte na drugu, dovodeći tako svaki put na ekran drugi skup komponenti. Postoji sličnost sa HyperCardom na Mac-u ili Toolbookom na Windowsima. U Javi se takav razmeštaj može koristiti kao niz ekrana za unos ako svi podaci ne stanu na jedan. Ako je potrebno prikazati više podataka, onda se može napraviti slide show.
Na primer, pogledajte sledeći aplet, CardTest, jeste jedan od Sunovih standardnih demo appleta. On koristi CardLayout za prebacivanje s jednog razmeštaja na drugi, pri čemu se na različite načine raspoređuju isti dugmici:
<APPLET CODE="CardTest.class" WIDTH=400 HEIGHT=200> </APPLET>
/*
* @(#)CardTest.java
*
* Copyright 2002 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
class CardPanel extends Panel {
ActionListener listener;
Panel create(LayoutManager layout) {
Button b = null;
Panel p = new Panel();
p.setLayout(layout);
b = new Button("one");
b.addActionListener(listener);
p.add("North", b);
b = new Button("two");
b.addActionListener(listener);
p.add("West", b);
b = new Button("three");
b.addActionListener(listener);
p.add("South", b);
b = new Button("four");
b.addActionListener(listener);
p.add("East", b);
b = new Button("five");
b.addActionListener(listener);
p.add("Center", b);
b = new Button("six");
b.addActionListener(listener);
p.add("Center", b);
return p;
}
CardPanel(ActionListener actionListener) {
listener = actionListener;
setLayout(new CardLayout());
add("one", create(new FlowLayout()));
add("two", create(new BorderLayout()));
add("three", create(new GridLayout(2, 2)));
add("four", create(new BorderLayout(10, 10)));
add("five", create(new FlowLayout(FlowLayout.LEFT, 10, 10)));
add("six", create(new GridLayout(2, 2, 10, 10)));
}
public Dimension getPreferredSize() {
return new Dimension(200, 100);
}
}
public class CardTest extends Applet
implements ActionListener,
ItemListener {
CardPanel cards;
public CardTest() {
setLayout(new BorderLayout());
add("Center", cards = new CardPanel(this));
Panel p = new Panel();
p.setLayout(new FlowLayout());
add("South", p);
Button b = new Button("first");
b.addActionListener(this);
p.add(b);
b = new Button("next");
b.addActionListener(this);
p.add(b);
b = new Button("previous");
b.addActionListener(this);
p.add(b);
b = new Button("last");
b.addActionListener(this);
p.add(b);
Choice c = new Choice();
c.addItem("one");
c.addItem("two");
c.addItem("three");
c.addItem("four");
c.addItem("five");
c.addItem("six");
c.addItemListener(this);
p.add(c);
}
public void itemStateChanged(ItemEvent e) {
((CardLayout)cards.getLayout()).show(cards,
(String)(e.getItem()));
}
public void actionPerformed(ActionEvent e) {
String arg = e.getActionCommand();
if ("first".equals(arg)) {
((CardLayout)cards.getLayout()).first(cards);
} else if ("next".equals(arg)) {
((CardLayout)cards.getLayout()).next(cards);
} else if ("previous".equals(arg)) {
((CardLayout)cards.getLayout()).previous(cards);
} else if ("last".equals(arg)) {
((CardLayout)cards.getLayout()).last(cards);
} else {
((CardLayout)cards.getLayout()).show(cards,(String)arg);
}
}
public static void main(String args[]) {
Frame f = new Frame("CardTest");
CardTest cardTest = new CardTest();
cardTest.init();
cardTest.start();
f.add("Center", cardTest);
f.setSize(300, 300);
f.show();
}
public String getAppletInfo() {
return "Demonstrates the
different types of layout managers.";
}
}
Upotreba CardLayout razmeštaja
Ovaj razmeštaj se kreira pomoću konstruktora CardLayout():
this.setLayout(new CardLayout());
Postoji još jedan konstruktor kojim se može odrediti razmak među komponentama:
this.setLayout(new CardLayout(3, 4));
Primer:
Neka komponente budu razmaknute 3 pixela horizontalno i 4 pixela vertikalno.
Svaka karta ima ime. Nova karta se kreira kad dodate komponentu karti
koja do tada nije uvedena. Komponente dodajete tako da navedete ime karte
i instancu komponente u metodi add():
this.setLayout(new CardLayout());
this.add("Sladoled", new Label("Volite i sladoled?"));
this.add("Sladoled", new Button("OK"));
this.add("Placanje", new Label("Nacin placanja?"));
this.add("Placanje", new Button("OK"));
this.add("Address", new Label("Nacin preuzimanja paketa"));
this.add("Address", new Button("Narucite"));
Često se karte imenuju po brojevima:
this.setLayout(new CardLayout());
this.add("1", new Label("Prva karta"));
this.add("2", new Label("Druga karta"));
this.add("3", new Label("Treca karta"));
this.add("4", new Label("Cetvrta karta"));
this.add("5", new Label("Peta karta"));
this.add("6", new Label("Sesta karta"));
Interno se popis karata i njihovih imena čuva u objekta tipa java.util.Hashtable,
a to znači da redosleda karata nije ugražen ili garantovan, već o
tome se stara programer.
Promena karata
Po pravilu svakoj karti se dodaje panel koji ima sopstveni LayoutManager.
Svaka karta mora biti snabdevena smernicama za navigaciju među kartama.
Ali, AWT nema ugrađen takav alat.
Kako jednu komponentu možete dodati na više od jedne karte, to svojstvo
je korisno, na primer, za kreiranje Choice selektora sa imenima svih karata
kao pomoći pri navigaciji.
Narednih pet metoda klase java.awt.CardLayout omogućuje promenu aktivne
karte.
U svim slučajevima treba specificirati kontejner unutar kog se prelazi
s karte na kartu. To može biti aplet, prozor ili panel koji je uređen u
skladu s tim razmeštajem.
public void first(Container parent)
public void next(Container parent)
public void previous(Container parent)
public void last(Container parent)
public void show(Container parent, String name)
GridLayout je koristan kad se želi razmeštaj više objekata bliskih veličina. Koristi se za sastavljanje liste checkboxova ili radio dugmića.
Primer koji raymešta checkboxove unutar devet redova i jedne kolone, što će apletu dati mnogo bolji i uredniji izgled. Uklonjen je programski kod za obradu događaja jer nije od značaja za ovaj primer.
import java.applet.*;
import java.awt.*;
public class Sastojci extends Applet {
TextField t;
double cena = 48.00;
public void init() {
this.setLayout(new GridLayout(9,1));
this.add(new Label("Zelite sladoled
sa ...?", Label.CENTER)); this.add(new Checkbox("Kakao"));
this.add(new Checkbox("Vanila"));
this.add(new Checkbox("Badem"));
this.add(new Checkbox("Jagoda"));
this.add(new Checkbox("Malaga")); this.add(new Checkbox("Banana"));
this.add(new Checkbox("Kafa"));
this.t = new TextField("$" + String.valueOf(cena));
this.t.setEditable(false);
this.add(this.t);
}
/* ovde moze doci kod za obradu dogadjaja
koji je iz ovog primera uklonjen */
}
<HTML>
<HEAD></HEAD>
<BODY>
<P>Izlaz apleta</p>
<P align="center">
<APPLET CODE="Sastojci.class" WIDTH=400 HEIGHT=400>
</APPLET>
<P> </p>
</BODY>
</HTML>
Ako se GridLaxout koristi npr. za razmeštaj dugmića, onda se može uočiti
da se oni uvećavaju da popune sebi dostupan prostor u svakoj ćeliji.
Na primer aplet koji razmešta 9 dugmića u tabelu 3x3 sa 10 piksela
razmakom između komponenti u oba pravca:
import java.awt.*;
public class Porodica extends java.applet.Applet {
GridLayout studenti = new GridLayout(3,3,10,10);
Button a1 = new Button("Marko");
Button a2 = new Button("Katarina");
Button a3 = new Button("Goran");
Button a4 = new Button("Janko");
Button a5 = new Button("Ana");
Button a6 = new Button("Petar");
Button a7 = new Button("Sandra");
Button a8 = new Button("Mika");
Button a9 = new Button("Branko");
public void init() {
setLayout(studenti);
add(a1);
add(a2);
add(a3);
add(a4);
add(a5);
add(a6);
add(a7);
add(a8);
add(a9);
}
}
Ako se aplet Porodica učita u appletviewer-u može se uočiti da u grid razmeštaju komponenta zauzima čitav prostor jedne ćelije, tj. dugmići menjaju veličinu pri promeni veličine Applet prozora, što razlikuje menadžer postavke toka od drugih.
Konstruktor za GridBagLayout je trivijalan, GridBagLayout() bez argumenata:
GridBagLayout gbl = new GridBagLayout();
setLayout(gbl);
Za razliku od upotrebe konstruktora za GridLayout(), ne specificira se broj redova ili kolona koje treba napraviti. To se određuje prema ćelijama koje konkretni program referencira. Ako npr. stavite komponentu u osmi red i drugu kolonu, Java će osigurati da bude bar devet redova i tri kolone (redovi i kolone se indeksiraju počevod od nulte). Ako kasnije stavite komponentu u deseti red i četvrtu kolonu, Java će dodati odgovarajući broj ćelija. Možete zamišljati konačnu mrežu, ali Java to ne mora znati kad kreirate GridBagLayout.
Za razliku od većine ostalih razmeštaja, referenca na objekt tipa GridBagLayout
biće potrebna kasnije u programu pa ga, dakle nećete kreirati anonimno,
unutar poziva metode setLayout().
Specifikacije GridBagConstraints
Svakoj komponenti koju kontroliše GridBagLayout pridružen je po jedan objekt iz klase java.awt.GridBagConstraints koji specificira položaj unutar površine za prikaz. Takav objekt zajedno sa minimalnom i preferiranom veličinom komponente određuje gde se i kako površina za prikaz smešta unutar apleta.
Konstruktor za GridBagConstraints() je trivijalan:
GridBagConstraints gbc = new GridBagConstraints();
Interakcija s objektom tipa GridBagConstraints odvija se preko jedanaest promenljivih (gridx, gridy, gridwidth, gridheight, weightx, weighty, achor, fill, insets, ipadx, ipady) i petnaest mnemoničkih konstanti (RELATIVE, REMAINDER, NONE, BOTH, HORIZONTAL, VERTICAL, CENTER, NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, NORTHWEST).
Primer apleta koji predstavlja masku za kalkulator.
Mreža (grid) za aplet Calculator
Evo sada mreže koja se koristi za razmeštaj kalkulatorovih komponenti.
U mreži ima više ćelija nego komponenti kalkulatora. Kalkulator ima jedan
TextField i 18 dugmića različitih veličina. Neke komponente zauzeće više
od jedne ćelije mreže. Na primer, TextField koji predstavlja kalkulatorov
display zauzeće četiri ćelije, (0, 0), (1, 0), (2, 0), and (3, 0).
(0, 0)
(1, 0)
(2, 0)
(3, 0)
(0, 1)
(1, 1)
(2, 1)
(3. 1)
(0, 2)
(1, 2)
(2, 2)
(3, 2)
(0, 3)
(1, 3)
(2, 3)
(3, 3)
(0, 4)
(1, 4)
(2, 4)
(3, 4)
(0, 5)
(1, 5)
(2, 5)
(3, 5)
Za svaku komponentu kreiraće se po jedan objekt tipa GridBagConstraints. Na primer za display, equals key i zero key
GridBagConstraints GBC_display = new GridBagConstraints();
GridBagConstraints GBC_bigequals = new GridBagConstraints();
GridBagConstraints GBC_0 = new GridBagConstraints();
Nakon što se postave vrednosti odgovarajućih atributa, taj
objekt će se pridružiti komponenti pomoću metode setConstraints() ovako:
gbl.setConstraints(display, GBC_display);
gb1.setConstraints(bigequals, GBC_bigequals;
gbl.setConstraints(b0, GBC_0);
Atributi gridx i gridy
Atributi gridx i gridy specificiraju x i y "koordinate",
tj. kolonu i vrstu ćelije u koju će doći levi gornji ugao komponente. Gornja
leva ćelija u našem primeru je ćelija (0, 0). Umjesto apsolutnih vrednosti
možemo staviti i mnemoničku konstantu GridBagConstraints.RELATIVE koja
kaže da će komponenta biti smeštena neposredno desno (gridx) ili neposredno
ispod (gridy) u odnosu na komponentu koja je pre toga posljednja bila dodana
kontejneru.
Naš kalkulator ima display u levom gornjem uglu apleta. Prema tome, gridx i gridy prve komponente (to je TextField) izgledaće:
GBC_display.gridx = 0;
GBC_display.gridy = 0;
Takođe, na primer, taster kalkulatora za znak jednakosti imaće
GBC_bigequals.gridx = 3;
GBC_bigequals.gridy = 4;
Taster za cifru 0 imaće
GBC_0.gridx = 0;
GBC_0.gridy = 5;
Atributi gridwidth i gridheight
Atributi gridwidth i gridheight specificiraju broj ćelija u vrsti (gridwidth) ili koloni (gridheight) koje će komponenta zauzeti. Ako ovde upišemo mnemoničku konstantu GridBagConstraints.REMAINDER, onda će komponenta zauzeti sve preostale ćelije u vrsti (za gridwidth) ili koloni (za gridheight).
Kalkulatorov display će zauzeti četiri ćelije po širini i jednu po visini:
GBC_display.gridwidth = 4; GBC_display.gridheight = 1;
Taster za znak jednakosti (equals key) je dve ćelije visok i jednu ćeliju širok, dakle
GBC_bigequals.gridwidth = 1;
GBC_bigequals.gridheight = 2;
Taster za cifru 0 imaće
GBC_0.gridwidth = 2;
GBC_0.gridheight = 1;
Atribut fill
Atribut fill specificira način na koji komponenta ispunjava prostor koji joj je dodeljen (u slučaju da je prostor veći od same komponente). Mnemoničke konstante koje koristite za postavljanje ove promenljive su:
GridBagConstraints.NONE: komponenta ne menja veličinu
GridBagConstraints.HORIZONTAL: Komponenta će se protezati preko cele
širine prostora koji joj je dodeljen, ali neće promeniti svoju visinu
GridBagConstraints.VERTICAL: Komponenta će se protezati preko cele
visine prostora koji joj je dodeljen, ali neće promeniti svoju širinu
GridBagConstraints.BOTH: Širina i visina komponente biće prilagođene
tako da komponenta zauzme celi prostor koji joj je dodeljen
U ovom primeru određeno je da se display širi horizontalno, a tasteri
u svim smerovima, npr. za taster cifre 0
GBC_display.fill = GridBagConstraints.HORIZONTAL;
GBC_0.fill = GridBagConstraints.BOTH;
Atributi ipadx i ipady
Svaka komponenta ima određenu minimalnu širinu i visinu i ne može se smanjivati ispod tih vrednosti. Ako su minimalne dimenzije komponente veće od dimenzija površine koje joj stoje na raspolaganju, biće prikazan samo deo komponente.
Atributi ipadx i ipady dozvoljavaju vam da povećate te minimalne dimenzije
tako da se rubovima komponente doda nešto prostora . Na primer, ako stavite
ipadx =2, to će garantovati da je komponenta najmanje 4 piksela šira od
svog normalnog minimuma. U našem primeru to nije potrebno.
Atribut Insets
Atribut insets je instanca klase java.awt.Insets. On specificira razmak između komponente i rubova površine na kojoj je smeštena. Za sve tastere u kalkulatoru odredili smo da to bude 3 piksela sa svake strane (što osigurava da susedni tasteri budu razmaknuti za 6 piksela), pa imamo na primer
GBC_bigequals.insets = new Insets(3, 3, 3, 3);
GBC_0.insets = new Insets(3, 3, 3, 3);
Atribut anchor
Kad je komponenta manje nego raspoloživa površina, atribut anchor specificira položaj unutar ćelije gde će komponentu postaviti. Mnemoničke konstante koje se za to koriste slične su onima za BorderLayout. To su
GridBagConstraints.CENTER
GridBagConstraints.NORTH
GridBagConstraints.NORTHEAST
GridBagConstraints.EAST
GridBagConstraints.SOUTHEAST
GridBagConstraints.SOUTH
GridBagConstraints.SOUTHWEST
GridBagConstraints.WEST
GridBagConstraints.NORTHWEST
Pretpostavljena vrednost je GridBagConstraints.CENTER. U tekućem primeru
to nije eksplicitno navedeno, jer su komponente dovoljno velike u odnosu
na raspoložive površine, tako da je centrirana pozicija zadovoljavajuća.
Atributi weightx i weighty
Atributi weightx i weighty određuju kako su ćelije distribuirane unutar
kontejnera ako njihova ukupna veličina bude manja od veličine kontejnera.
Sa težinama 0 (default) sve ćelije zauzimaju najmanje što mogu i sve se
sabije prema centru. Sav dodatni prostor je izguran prema rubovima kontejnera.
Primer za GridBagLayout
Pogledajmo sada init() metod sa razmeštajem kalkulatorovih
tastera:
public void init () {
GridBagLayout gbl = new GridBagLayout();
setLayout(gbl);
// dodavanje displeja za gornje četiri ćelije
GridBagConstraints GBC_display = new GridBagConstraints();
GBC_display.gridx = 0;
GBC_display.gridy = 0;
GBC_display.gridwidth = 4;
GBC_display.gridheight = 1;
GBC_display.fill = GridBagConstraints.HORIZONTAL;
// dodavanje tekstualnog polja
TextField display = new TextField(12);
gbl.setConstraints(display, GBC_display);
add(display);
// dodavanje claer tastera kalkulatora
GridBagConstraints GBC_clear = new GridBagConstraints();
GBC_clear.gridx = 0;
GBC_clear.gridy = 1;
GBC_clear.gridwidth = 1;
GBC_clear.gridheight = 1;
GBC_clear.fill = GridBagConstraints.BOTH;
GBC_clear.insets = new Insets(3, 3, 3, 3);
// dodavanje dugmića
Button clear = new Button("C");
gbl.setConstraints(clear, GBC_clear);
add(clear);
// dodavanje znaka jednakosti
GridBagConstraints GBC_equals = new GridBagConstraints();
GBC_equals.gridx = 1;
GBC_equals.gridy = 1;
GBC_equals.gridwidth = 1;
GBC_equals.gridheight = 1;
GBC_equals.fill = GridBagConstraints.BOTH;
GBC_equals.insets = new Insets(3, 3, 3, 3);
// dodavanje dugmeta =
Button equals = new Button("=");
gbl.setConstraints(equals, GBC_equals);
add(equals);
// dodavanje dugmeta /
GridBagConstraints GBC_slash = new GridBagConstraints();
GBC_slash.gridx = 2;
GBC_slash.gridy = 1;
GBC_slash.gridwidth = 1;
GBC_slash.gridheight = 1;
GBC_slash.fill = GridBagConstraints.BOTH;
GBC_slash.insets = new Insets(3, 3, 3, 3);
// dugme /
Button slash = new Button("/");
gbl.setConstraints(slash, GBC_slash);
add(slash);
// taster *
GridBagConstraints GBC_times = new GridBagConstraints();
GBC_times.gridx = 3;
GBC_times.gridy = 1;
GBC_times.gridwidth = 1;
GBC_times.gridheight = 1;
GBC_times.fill = GridBagConstraints.BOTH;
GBC_times.insets = new Insets(3, 3, 3, 3);
// dodavanje dugmeta *
Button star = new Button("*");
gbl.setConstraints(star, GBC_times);
add(star);
// taster 7
GridBagConstraints GBC_7 = new GridBagConstraints();
GBC_7.gridx = 0;
GBC_7.gridy = 2;
GBC_7.gridwidth = 1;
GBC_7.gridheight = 1;
GBC_7.fill = GridBagConstraints.BOTH;
GBC_7.insets = new Insets(3, 3, 3, 3);
// dodavanje dugmeta
Button b7 = new Button("7");
gbl.setConstraints(b7, GBC_7);
add(b7);
// taster 8
GridBagConstraints GBC_8 = new GridBagConstraints();
GBC_8.gridx = 1;
GBC_8.gridy = 2;
GBC_8.gridwidth = 1;
GBC_8.gridheight = 1;
GBC_8.fill = GridBagConstraints.BOTH;
GBC_8.insets = new Insets(3, 3, 3, 3);
Button b8 = new Button("8");
gbl.setConstraints(b8, GBC_8);
add(b8);
GridBagConstraints GBC_9 = new GridBagConstraints();
GBC_9.gridx = 2;
GBC_9.gridy = 2;
GBC_9.gridwidth = 1;
GBC_9.gridheight = 1;
GBC_9.fill = GridBagConstraints.BOTH;
GBC_9.insets = new Insets(3, 3, 3, 3);
Button b9 = new Button("9");
gbl.setConstraints(b9, GBC_9);
add(b9);
// taster -
GridBagConstraints GBC_minus = new GridBagConstraints();
GBC_minus.gridx = 3;
GBC_minus.gridy = 2;
GBC_minus.gridwidth = 1;
GBC_minus.gridheight = 1;
GBC_minus.fill = GridBagConstraints.BOTH;
GBC_minus.insets = new Insets(3, 3, 3, 3);
// dodavanje dugmeta
Button minus = new Button("-");
gbl.setConstraints(minus, GBC_minus);
add(minus);
// 4
GridBagConstraints GBC_4 = new GridBagConstraints();
GBC_4.gridx = 0;
GBC_4.gridy = 3;
GBC_4.gridwidth = 1;
GBC_4.gridheight = 1;
GBC_4.fill = GridBagConstraints.BOTH;
GBC_4.insets = new Insets(3, 3, 3, 3);
Button b4 = new Button("4");
gbl.setConstraints(b4, GBC_4);
add(b4);
GridBagConstraints GBC_5 = new GridBagConstraints();
GBC_5.gridx = 1;
GBC_5.gridy = 3;
GBC_5.gridwidth = 1;
GBC_5.gridheight = 1;
GBC_5.fill = GridBagConstraints.BOTH;
GBC_5.insets = new Insets(3, 3, 3, 3);
Button b5 = new Button("5");
gbl.setConstraints(b5, GBC_5);
add(b5);
GridBagConstraints GBC_6 = new GridBagConstraints();
GBC_6.gridx = 2;
GBC_6.gridy = 3;
GBC_6.gridwidth = 1;
GBC_6.gridheight = 1;
GBC_6.fill = GridBagConstraints.BOTH;
GBC_6.insets = new Insets(3, 3, 3, 3);
Button b6 = new Button("6");
gbl.setConstraints(b6, GBC_6);
add(b6);
// taster +
GridBagConstraints GBC_plus = new GridBagConstraints();
GBC_plus.gridx = 3;
GBC_plus.gridy = 3;
GBC_plus.gridwidth = 1;
GBC_plus.gridheight = 1;
GBC_plus.fill = GridBagConstraints.BOTH;
GBC_plus.insets = new Insets(3, 3, 3, 3);
Button plus = new Button("+");
gbl.setConstraints(plus, GBC_plus);
add(plus);
GridBagConstraints GBC_1 = new GridBagConstraints();
GBC_1.gridx = 0;
GBC_1.gridy = 4;
GBC_1.gridwidth = 1;
GBC_1.gridheight = 1;
GBC_1.fill = GridBagConstraints.BOTH;
GBC_1.insets = new Insets(3, 3, 3, 3);
Button b1 = new Button("1");
gbl.setConstraints(b1, GBC_1);
add(b1);
GridBagConstraints GBC_2 = new GridBagConstraints();
GBC_2.gridx = 1;
GBC_2.gridy = 4;
GBC_2.gridwidth = 1;
GBC_2.gridheight = 1;
GBC_2.fill = GridBagConstraints.BOTH;
GBC_2.insets = new Insets(3, 3, 3, 3);
Button b2 = new Button("2");
gbl.setConstraints(b2, GBC_2);
add(b2);
GridBagConstraints GBC_3 = new GridBagConstraints();
GBC_3.gridx = 2;
GBC_3.gridy = 4;
GBC_3.gridwidth = 1;
GBC_3.gridheight = 1;
GBC_3.fill = GridBagConstraints.BOTH;
GBC_3.insets = new Insets(3, 3, 3, 3);
Button b3 = new Button("3");
gbl.setConstraints(b3, GBC_3);
add(b3);
GridBagConstraints GBC_bigequals = new GridBagConstraints();
GBC_bigequals.gridx = 3;
GBC_bigequals.gridy = 4;
GBC_bigequals.gridwidth = 1;
GBC_bigequals.gridheight = 2;
GBC_bigequals.fill = GridBagConstraints.BOTH;
GBC_bigequals.insets = new Insets(3, 3, 3, 3);
Button bigequals = new Button("=");
gbl.setConstraints(bigequals, GBC_bigequals);
add(bigequals);
GridBagConstraints GBC_0 = new GridBagConstraints();
GBC_0.gridx = 0;
GBC_0.gridy = 5;
GBC_0.gridwidth = 2;
GBC_0.gridheight = 1;
GBC_0.fill = GridBagConstraints.BOTH;
GBC_0.insets = new Insets(3, 3, 3, 3);
Button b0 = new Button("0");
gbl.setConstraints(b0, GBC_0);
add(b0);
GridBagConstraints GBC_decimal = new GridBagConstraints();
GBC_decimal.gridx = 2;
GBC_decimal.gridy = 5;
GBC_decimal.gridwidth = 1;
GBC_decimal.gridheight = 1;
GBC_decimal.fill = GridBagConstraints.BOTH;
GBC_decimal.insets = new Insets(3, 3, 3, 3);
Button bdecimal = new Button(".");
gbl.setConstraints(bdecimal, GBC_decimal);
add(bdecimal);
}
Primer apleta sa pop-up okvirom prozora
Prethodni aplet sa dodatim dijalog prozorom
Primer
apleta sa panelima i upravljanjem dogadjajima - rgb2hsb
Šta je Container?
Kontejner je komponenta koja može sadržati druge komponente. On je
uvek instanca klase java.awt.Container koja je podklasa od java.awt.Component,
pa su, dakle, kontejneri i sami komponente.
Applet je primer kontejnera, kao i prozori (windows), okviri (frames), dijalozi (dialogs) i paneli (panels). Kontejneri mogu sadržati druge kontejnere.
Svaki kontejner ima svoj Layout manager koji određuje način pozicioniranja komponenata unutar kontejnera.
Apleti osiguravaju već gotov kontejner i pretpostavljeni Layout manager. To je FlowLayout.
Paneli su podklase od java.awt.Panel. Panel se nalazi unutar drugog kontejnera ili možda unutar browserovog prozora. Paneli nisu samostalni. Appleti su primer panela.
Prozori su podklase od java.awt.Window. Prozor je samostalan. Postoji
više vrsta prozora, na primer okviri (frames) i dijalozi(dialogs). Okviri
su podklase od java.awt.Frame. Klasa Frame daje proyor sa naslovnom
trakom, dugmad za zatvaranje prozora i ostale mogućnosti prozora vezanig
za platformu (operativni sistem). Okviri omogućuju i dodavanje menija.
Dijalozi su podklase od java.awt.Dialog. Dialog je privremeni, nestalni
prozor koji postoji samo da prenese neke informacije ili primi neki ulaz
od korisnika. Na primer, FileDialog je podklasa klase Dialog
koja
omogućava standardne dijalog boksove za selekciju datoteka. Obično se koristi
u Java aplikacijama zbog sigurnosnih ograničenja apleta.
Paneli
Svaki Panel je zapravo generički Container čija glavna uloga je grupisanje
komponenti na jedno mesto.
Pri radu sa panelima važno je znati je da
Paneli se kreiraju poyivom konstruktora Panel klase:
Panel mojPanel=new Panel();
Metod postavke za panel se određuje pozivom setLayout() metoda na tom panelu. Funkcionisanje je isto kao kod istoimenog metoda primenjenog na aplet prozor, jer i Applet i Panel predstavljaju podklase Container klase i nasleđuju neporomenjeno ponašanje iz te superklase.
Kako svaki Panel može imati sopstveni LayoutManager, onda se sa panelima možete učiniti mnogo toga što inače nije moguće sa samo jednim Layout managerom.
Na primer, pretpostavimo da želite da se TextArea nalazi u centru appleta, a dugme ispod nje, na "jugu":
To se ne možete postići s jednim jedinim Layout managerom. Na primer, BorderLayout bi proširio Button preko čitave širine appleta. S druge strane FlowLayout ne bi učinio da TextArea bude dovoljno velika.
Umesto toga, može se kreirati aplet koji ima BorderLayout, a TextArea
mu se nalazi u centru. Potom kreirati Panel, postavite njegov LayoutManager
na FlowLayout, dodate button tom panelu i onda dodati panel južnom delu
appleta.
Evo primera:
import java.applet.*;
import java.awt.*;
public class Panel1 extends Applet {
public void init() {
this.setLayout(new BorderLayout());
this.add("Center", new TextArea());
Panel p = new Panel();
p.setLayout(new FlowLayout(FlowLayout.CENTER));
p.add(new Button("OK"));
this.add("South", p);
}
}
<APPLET CODE="Panel1.class" WIDTH=300 HEIGHT=200>
</APPLET>
U ovom primeru bitno je razlikovati dodavanje komponente apletu (add(...) ili this.add(...)) od dodavanja komponente panelu (p.add(...)).
Ali, nije od značaja da li je prvo dodat panel appletu, pa onda button panelu ili obrnuto.
Druga česta upotreba panela je za postavljanje niza checkboxova koji
imaju GridLayout s jednom kolonom.
Ugnježdeni paneli
Ponekad je potrebno nekoliko instanci istog LayoutManagera. Pogledajmo
opet primer kalkulatora.
S jedne strane izgleda kao da ga je jednostavno implementirati, jer se radi sa 18 Button-a i TextField-om. S druge strane, gotovo svi tasteri su jednake veličine, samo su dva tastera i display nešto veći. Gotovo bi se mogao koristiti GridLayout, ali ipak ne sasvim. Paneli su jedan od načina rešavanja ovog problema.
Evo sada rešenja kalkulatora uz upotrebu samo GridLayout i ugnježdenih panela.
import java.applet.*;
import java.awt.*;
public class Calculator extends Applet {
TextField screen;
public void init () {
this.setLayout(new GridLayout(3, 1, 3, 3));
Panel A1 = new Panel(); this.add(A1);
Panel A2 = new Panel(); this.add(A2);
Panel A3 = new Panel(); this.add(A3);
A1.setLayout(new GridLayout(2, 1)); screen = new TextField(12); A1.add(screen);
Panel B1 = new Panel();
B1.setLayout(new GridLayout(1, 4, 3, 3));
B1.add(new Button("C")); B1.add(new
Button("=")); B1.add(new Button("/"));
B1.add(new Button("*"));
A1.add(B1);
A2.setLayout(new GridLayout(2, 4, 3, 3));
A2.add(new Button("7")); A2.add(new
Button("8")); A2.add(new Button("9"));
A2.add(new Button("-"));
A2.add(new Button("4")); A2.add(new
Button("5")); A2.add(new Button("6"));
A2.add(new Button("+"));
A3.setLayout(new GridLayout(1, 2, 3, 3));
// 1, 2 and 0
Panel B2 = new Panel(); B2.setLayout(new
GridLayout(2, 1, 3, 3)); // 1 and 2
Panel C1 = new Panel(); C1.setLayout(new
GridLayout(1, 2, 3, 3));
C1.add(new Button("1")); C1.add(new
Button("2")); B2.add(C1); B2.add(new
Button("0"));
// 3, . and =
Panel B3 = new Panel();
B3.setLayout(new GridLayout(1, 2, 3, 3)); // 3 and .
Panel C2 = new Panel(); C2.setLayout(new GridLayout(2,
1, 3, 3)); C2.add(new Button("3"));
C2.add(new Button(".")); B3.add(C2);
B3.add(new Button("=")); A3.add(B2);
A3.add(B3);
}
public Insets insets() {
return new Insets(5, 5, 5, 5);
}
/* event handling Jave 1.0 . */
public boolean action(Event e, Object arg) {
if (e.target instanceof Button) {
screen.setText((String) arg);
return true; }
return false;
}
}
<APPLET CODE="Calculator.class" WIDTH=150 HEIGHT=150>
</APPLET>
Prozori (windows)
Klasa java.awt.Window i njene podklase omogućuju kreiranje samostalnih
prozora. Samostalni prozori su česti u aplikacijama koje za komunikaciju
s korisnikom koriste AWT umesto komandne linije. Takođe osiguravaju dodatni
prostor za applete.
Klasa java.awt.Window je podklasa od java.awt.Container, ali je nezavisna od ostalih kontejnera, tj. sam nije sadržan u drugim kontejnerima. Možete mu dodavati komponente kao što je Button ili TextField. Može imati svoj vlastiti LayoutManager. Možete crtati direktno pomoću njegove paint() metode. Sve što možete raditi u appletovom panelu, možete raditi i u prozoru.
Uobičajeno je da se klasa java.awt.Window ne koristi direktno. Umesto toga radi se sa njenim podklasama, na primer java.awt.Frame ili java.awt.Dialog, zavisno od vaših potreba. Frame je okvir koji može imati svoj scrollbar, korisnik mu može menjati veličinu ili položaj i postojaće na ekranu dok god korisnika zanima njegov sadržaj.
Nasuprot tome, dijalog neće imati meni, obično mu se ne može menjati
veličina iako je moguće pomerati ga. Njegova funkcija je prenošenje određene
informacije (unosa) od korisnika ili izdavanje upozorenja. Vidljiv je samo
dok ne dobije odgovarajući input ili dok korisnik ne potvrdi da je pročitao
informaciju s njega.
Okviri (frames)
Okviri su korisni za kompleksnije aplikacije. Omogućuju odvajanje različitih
funkcija ili podataka u različite prozore. Na primer, aplikacija za crtanje
može imati nekoliko različitih slika s raznim statusima završenosti u različitim
prozorima. Ili možda može imati jednu sliku, ali u drugom prozoru paletu
s raznim četkama i bojama. Svaki od tih prozora bio bi Frame.
Sve što je potrebno za kreiranje okvira i rad s njima nalazi se u klasi java.awt.Frame. Za kreiranje novog okvira bez naslovne pruge koristi se konstruktor Frame() bez argumenata.
Frame f = new Frame();
Češće će ipak biti potrebno dati okviru naslov:
Frame f = new Frame("Moj Prozor");
Okviri nasleđuju klasu java.awt.Container, te im se mogu dodavati komponente.
Za razliku od panela i appleta, pretpostavljeni LayoutManager za okvire
je BorderLayout, a ne FlowLayout. To se , naravno, može izmeniti pomoću
metode setLayout():
f.setLayout(new FlowLayout());
Okviri nasleđuju i klasu java.awt.Component, te imaju i metode paint() i update(). Ako se želi crtati unutar okvira i procesirati događaj ručno kao u appletima, onda se kreira podklasa od Frame i dodaje joj se odgovarajući listener. Uglavnom sve što je rađeno sa vlastitim podklasama od java.awt.Applet može se raditi i sa sopstvenim podklasama od java.awt.Frame.
Ali, najčešće se koriste komponente. Da bi se komponenta dodala okviru,
poziva se njegova metodu add() isto kao što je pozivana appletova
metoda add(). Jedina razlika je što često se ta metoda poziva
izvan klase Frame, tako da će biti potrebno dodati odgovarajući prefiks
koji pokazuje na okvir. Drugim rečima, ako postoji okvir Frame f, poziva
se
f.add(new Button("OK");
umesto
this.add(new Button("OK"));
Naravno, to zavisi koja klasa je tekuća klasa kad pozivate add(). Ako je pozivate iz neke od podklasa klase Frame, onda to neće biti potrebno.
Kako je pretpostavljeni layout za frame BorderLayout, potrebno je specificirati
da li komponentu dodajete na North, South, East, West ili Center. Evo primera
koji pokazuje kako se dodaje centrirana labela u centar okvira Frame f:
f.add("Center", new Label("Ovo jeste okvir", Label.CENTER));
Ili
f.add(new Label("Ovo jeste okvir", Label.CENTER), BorderLayout.CENTER);
Veličina i pozicija bilo kojeg datog okvira je nepredvidljiva ako se
ne specificirate. Veličina se zadaje pomoću metode setSize():
f.setSize(150,150);
Ta veličina ne uključuje naslovnu prugu, pa to treba zasebno uzeti u
obzir. Da biste doznali visinu naslovne pruge za okvir, poziva se njegov
metod insets() i pogledati atribut top rezultirajućeg objekta iz java.awt.Insets.
To će biti visina naslovne pruge:
int TitleBarVisina
= f.insets().top;
Postavljanje okvira na željenu poziciju na ekranu obavlja se pomoću metode setLocation(int x, int y). Ovdje se x i y računaju prema ekranu, ne prema appletu.
Kad se prozor kreira, on je u početku nevidljiv. Dodavanje komponenti
dobro je obaviti dok je prozor još nevidljiv, inače će korisnik morati
gledati skakanje komponenti i nepredvidljivo pomicanje prozora dok se slika
ne stabilizuje. Kad ste završili s dodavanjem komponenti, okvir se mora
učiniti vidljivim pozivom metoda show():
f.show();
Događaji vezani uz prozore
Budući da je java.awt.Window podklasa od java.awt.Component, znači
da objekti tipa Window mogu lansirati događaje. Ti događaji su objekti
tipa java.awt.event.WindowEvent. To su:
WindowEvent.WINDOW_ACTIVATED
WindowEvent.WINDOW_CLOSED
WindowEvent.WINDOW_CLOSING
WindowEvent.WINDOW_DEACTIVATED
WindowEvent.WINDOW_DEICONIFIED
WindowEvent.WINDOW_ICONIFIED
WindowEvent.WINDOW_OPENED
Da biste mogli odgovarati na te događaje, morate uz objekt tipa java.awt.Window registrovati odgovarajući listener, dakle objekt neke klase koja implementira interface java.awt.event.WindowListener. Ovaj interfejs propisuje sledeće metode:
public abstract void windowOpened(WindowEvent e)
public abstract void windowClosing(WindowEvent e)
public abstract void windowClosed(WindowEvent e)
public abstract void windowIconified(WindowEvent e)
public abstract void windowDeiconified(WindowEvent e)
public abstract void windowActivated(WindowEvent e)
public abstract void windowDeactivated(WindowEvent e)
Primer događaja na prozorima
Na primer, prozori se ne zatvaraju sami od sebe nego se moraju eksplicitno
zatvoriti. Sledeća podklasa klase Frame odgovara na pokušaj zatvaranja
tako da pozove metode setVisible(false) i dispose().
import java.awt.*;
import java.awt.event.*;
public class ZatvorenFrame extends Frame implements WindowListener
{
public ZatvorenFrame() {
this.addWindowListener(this);
}
public ZatvorenFrame(String s) {
super(s);
this.addWindowListener(this);
}
public void windowClosing(WindowEvent e) {
this.setVisible(false);
this.dispose();
}
public void windowOpened(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
}
Može se aktivirati pomoću sledećeg apleta:
import java.applet.Applet;
import java.awt.*;
public class ZatvorenFrameApplet extends Applet {
public void init() {
ZatvorenFrame cf = new ZatvorenFrame();
cf.setSize(150,150);
cf.setLocation(100,100);
cf.show();
}
}
<APPLET CODE="ZatvorenFrameApplet.class" WIDTH=200 HEIGHT=100>
</APPLET>
Kombinovanje apleta i aplikacija
Apletu je potreban okvir da bi se izvršavao koji po pravilu obezbeđuje
web browser.Ali mogu se kreirati instance korisničkog appleta unutar nekog
okvira korisničke aplikacije. Na taj način može se pisati kod koji je istovremeno
i applet i aplikacija.
Da bi se applet pretvorio u aplikaciju, dodaje mu se sledeća main() metodu (smatrati da mojApplet je naziv korisničkog appleta):
public static void main(String args[]) {
mojApplet a = new mojApplet();
a.init();
a.start();
Frame appletFrame = new Frame("Applet Prozor");
appletFrame.add("Center", a);
appletFrame.setSize(150,150);
appletFrame.setLocation(100,100);
appletFrame.show();
}
U prvom redu nalazi se deklaracija standardne main() metode koja se
koristi za aplikacije pokretane iz komandne linije.
Ako se applet izvršava unutar web browsera ili applet viewera, taj
metod biće ignorisan. Izvršiće se samo ako se applet pokrene kao samostalni
program.
Red 2 kreira instancu korisničkog appleta.
U redovima 3 i 4 poziva se appletov init() i start() metod. To inače
radi web browser za vas, ali ako se program izvršava samostalno, morate
to sami učiniti.
Nakon što je kreiran aplet, potreban je Frame u koji ćete ga smestiti. U redu 5 to se obavlja pomoću uobičajenog konstruktora Frame(). Ovde se možete promeniti naslov okvira da odgovara korisničkoj aplikaciji.
U redu 6 dodaje se applet u taj Frame. Budući da je LayoutManager za Frame po pretpostavci BorderLayout, applet će biti dodan u centar. Inače, java.applet.Applet je podklasa od java.awt.Component pa je u redu dodati ga na neki Frame.
Red 7 zadaje veličinu za Frame:150 x 150 pixela. Ako se program izvršava kao applet, te vrednosti se mogu dobiti iz parametara width i height, ali ako se izvršava samostalno, morate osmisliti neke veličine. Možete ih eventualno učitati kao argumente s komandne linije.
Red 8 postavlja Frame na poziciju (100, 100). Ako poziciju sami ne zadate, ona će biti nepredvidljiva,
Red 9 čini Frame vidljivim i applet je sad spreman za izvršavanje, unutar browsera ili izvan njega.
Napomena: Čak i ako imaju Frame, appleti ipak nisu isto što i aplikacije.
Kad se applet transformiše u aplikaciju na opisani način, mora se osigurati
da se program ne oslanja na metode koje imaju smisla jedino u appletima.
Na primer, metoda getParameter() nema smisla izvan appleta. Isto tako,
argumente s komandne linije možete učitavati samo u aplikacijama. Nadalje,
aplikacije imaju manje sigurnosnih restrikcija nego appleti pa program
koji dobro radi kao aplikacija može proizvesti mnoštvo sigurnosnih izuzetaka
(java.lang.SecurityException).
Dijalozi
Okviri su korisni kao prozori koji će se neko vreme zadržati na ekranu,
na primer u svrhu editovanja nekog teksta i slično. Za razliku od njih,
dijalozi koje implementira klasa java.awt.Dialog, po prirodi su kratkotrajni
i služe samo kao sredstvo za kratki input ili upozorenje korisniku.
Slično kao java.awt.Frame, java.awt.Dialog je podklasa od java.awt.Window pa dakle i od java.awt.Container i java.awt.Component. Prema tome, mnogo toga što znate o okvirima primjenjuje se i na dijaloge. Možete ih pomerati, menjati im veličinu i dodavati im komponente skoro isto kao i u slučaju okvira. Postoje, međutim, dve značajne razlike:
Okvir (frame) može imati prugu menija (menu bar) dok dijalog to ne može
Dijalog može biti modalan, dok okvir ne može
Modalni dijalog blokira komunikaciju sa svim drugim aplikacijama sve
dok ne dobije odgovarajući input od korisnika. Ne može se pomerati i ne
dozvoljava korisniku prelaz u drugi prozor istog programa. Na nekim platformama
ne dozvoljava čak i odlazak u prozore drugih programa.
Ne-modalni dijalozi se postavljaju pri aktiviranju, ali ne sprečavaju
korisnika da radi druge stvari dok su oni vidljivi.
Metode za dijaloge
Budući da su dijalozi komponente, oni mogu, kao i okviri, koristiti
metode kao što su setLocation() ili setSize(). Za dijaloge imamo konstruktore
koji im daju ili ne daju naslov, pa možemo, staviti:
Dialog d = new Dialog(new Frame(), false);
Prvi argument je roditeljski frame za taj dijalog, dok je drugi
tipa boolean i određuje hoće li dijalog biti modalan (true) ili ne (false).
Modalni dijalozi su modalni u odnosu na svoj roditeljski frame, dakle privremeno
sprečavaju unos u taj okvir, ali ne i u druge okvire.
Ako za prvi argument stavite null dijalog će izbaciti izuzetak, java.lang.IllegalArgumentException.
Ako kreirate roditeljski frame direktno unutar poziva konstruktora kao u prethodnom primeru, dijalog ne može biti modalan.
Ima još i nekih manjih razlika između okvira i dijaloga, npr.:
Korisnik može menjati položaj i veličinu većini okvira, dok dijalozima
u pravilu ne može.
Okviri obično imaju naslovne pruge.
Dijalogu možete omogućiti promenjivost veličine pomoću metode setResizable():
d.setResizable(true);
Možete mu dati naslovnu prugu tako da ga kreirate pomoću sledećeg konstruktora::
Dialog d = new Dialog(new Frame(), "Moj Dialog Prozor", false);
Sve ostale metode i postupci za dijaloge isti su kao i za okvire.
Sledeći primer prikazuje jednostavni ne-modalni dijalog sa OK buttonom i bez naslovne pruge.
import java.applet.*;
import java.awt.*;
public class DialogPrimer extends Applet {
public void init() {
Dialog mojDialog = new Dialog(new
Frame(), false);
mojDialog.setLocation(320,240);
myDialog.add("North", new Label("Pozdrav!"));
myDialog.add("South", new Button("OK"));
myDialog.pack();
myDialog.show();
}
}
<APPLET CODE="DialogPrimer.class"
WIDTH=150 HEIGHT=150>
</APPLET>
Pisanje podklasa klase Dialog
Prethodni primer je bio samo ilustracije radi, jer po pravilu, najčešća
upotreba dijaloga je putem kreiranja vlastitih podklasa od java.awt.Dialog
i i instanciranja iz glavnog programa.
Na primer, jedan od jednostavnijih uobičajenih dijaloga je ispis poruke
koju korisnik treba pročitati i potvrditi to pritiskom na OK dugme:
import java.awt.*;
import java.awt.event.*;
public class YesNoDialog extends Dialog implements ActionListener {
public YesNoDialog(Frame parent, String message) {
super(parent, true);
this.add("Center", new Label(message));
Panel p = new Panel();
p.setLayout(new FlowLayout());
Button yes = new Button("Yes");
yes.addActionListener(this);
p.add(yes);
Button no = new Button("No");
no.addActionListener(this);
p.add(no);
this.add("South", p);
this.setSize(350,100);
this.setLocation(100, 200);
}
public void actionPerformed(ActionEvent e) {
this.setVisible(false);
this.dispose();
}
}
import java.applet.Applet;
import java.awt.*;
public class Upozorenje1 extends Applet {
public void init () {
Dialog d = new YesNoDialog(new Frame(),
"Da li ste sigurni da nikad necete programirati?");
d.show();
}
}
<APPLET CODE="Upozorenje1.class"
WIDTH=300 HEIGHT=200>
</APPLET>
Šta je meni?
Java omogućuje postavljanje menija na frameove (dijalozima se meniji
ne mogu dodavati). Za applete to i nije tako bitno, ali u aplikacijama
je najčešće nužno.
Meniji su sastavljeni od tri hijerarhijska elementa Prvi element je pruga ili traka menija (menu bar). To je set menija koji se pojavljuju duž prozora.Nalazi se na gornjem rubu ekrana kod Macintosha ili na gornjem rubu prozora kod Windowsa ili Motifa.
Svaka pruga menija sadrži bar jedan meni (menu). Meni su organizirani poi temama. Često susrećemo File, Edit i tako dalje.
Svaki meni sadrži bar jednu opciju (menu item). Opcije su obično pojedinačne akcije kao Open, Print, Cut ili Copy. Opcije nisu prikazane dok meni nije aktivan. Dva ili više menija ne mogu biti istovremeno aktivni.
Klase menija
Paket AWT sadrži nekoliko glavnih klasa za upravljanje menijima:
java.awt.Menu
java.awt.MenuBar
java.awt.MenuItem
java.awt.PopupMenu
Da bi se koristili meniji, biće potreban bar jedan primerak iz klase MenuBar sa jednim ili više primeraka klase Menu, a za svakog nekoliko primeraka MenuItem. Meniji iz klase PopupMenu se pojavljuju kao samostalni element.
Klasa java.awt.MenuComponent je poslednja nadklasa svih ovih klasa,
a ona je opet podklasa od java.lang.Object. Prema tome, pruge menija, izbornici
i opcije nisu komponente i ne mogu se dodavati kontejnerima na uobičajeni
način.
java.lang.Object
|
+--java.awt.MenuComponent
|
+--java.awt.MenuBar
|
+--java.awt.MenuItem
|
+--java.awt.Menu
|
+--java.awt.PopupMenu
Uošava se da su MenuBar i MenuItem podklase od MenuComponent. Menu je
podklasa od MenuItem (ovo zvuči malo neobično, ali meni je zaista opcija,
samo se dodaje pruzi menija). Nadalje, MenuBar implementira interface java.awt.MenuContainer.
Kreiranje menija
Poželjno je potpuno izgraditi menije pre nego ih prikažete. Tipični
redosled akcija je:
kreirajte novi objekt tipa MenuBar.
kreirajte novi objekt tipa Menu.
dodajte opcije objektu tipa Menu.
ako je potrebno, ponovite korake 2 i 3.
dodajte objekt tipa MenuBar objektu tipa Frame.
Novi objekt tipa MenuBar kreira se ovako:
MenuBar myMenubar = new MenuBar();
Za kreiranje novog objekta tipa Menu koristi se konstruktor Menu(String
title). Dodajte mu naslov koji želite dati meniju. Na primer, za kreiranje
menija File i Edit, napravite:
Menu fileMenu = new Menu("File");
Menu editMenu = new Menu("Edit");
Opcije, MenuItema kreiraju se slično, pomoću konstruktora MenuItem(String
menutext). Dajte mu potreban naslov, na primer:
MenuItem Cut = new MenuItem("Cut");
Objekte tipa MenuItem kreirate unutar odgovarajućih objekata tipa Menu
kojima pripadaju, isto kao što ste komponente kreirali unutar odgovarajućih
razmeštaja. Izbornici imaju add() metode koje kao argument uzimaju objekte
tipa MenuItem. Evo kako biste napravili meni Edit i dodali mu opcije
Undo, Cut, Copy, Paste, Clear i Select All:
Menu editMenu = new Menu("Edit");
editMenu.add(new MenuItem("Undo"));
editMenu.addSeparator();
editMenu.add(new MenuItem("Cut"));
editMenu.add(new MenuItem("Copy"));
editMenu.add(new MenuItem("Paste"));
editMenu.add(new MenuItem("Clear"));
editMenu.addSeparator();
editMenu.add(new MenuItem("Select All"));
Metoda addSeparator() dodaje horizontalnu crtu preko izbornika. Koristi se za logičko razdvajanje funkcija na meniju.
Kad kreirate menije, dakle objekte tipa Menu, dodaćete ih pruzi menija, objektu tipa MenuBar koristeći MenuBarovu metodu add(Menu m) ovako:
myMenubar.add(fileMenu);
myMenubar.add(editMenu);
Konačno, kad je MenuBar gotov, dodaćete ga okviru, dakle objektu tipa
Frame koristeći se frameovom metodom setMenuBar(MenuBar mb). Ako imate
Frame f onda bi to izgledalo ovako:
f.setMenuBar(myMenuBar);
Primer menija
Korisnički interfejs može imati mnogo opcija, čak i po više stotina.
Sve njih staviti u init() metodu bilo bi nepraktično. Uobičajeno je kreirati
odvojene metode koje grade pojedinačni meni i dodati ih pruzi menija. Sledeći
primer kreira dva standardna izbornika, File i Edit.
import java.applet.*;
import java.awt.*;
public class MenuPrimer extends Applet {
public void init () {
Frame f = new Frame("Prozor s menijem");
f.add("Center", new Label("Pogledajte meni", Label.CENTER));
f.setSize(this.getSize().width, this.getSize().height);
f.setLocation(320,240);
MenuBar myMenuBar = new MenuBar();
this.makeFileMenu(myMenuBar);
this.makeEditMenu(myMenuBar);
f.setMenuBar(myMenuBar);
f.show();
}
void makeEditMenu(MenuBar mb) {
Menu editMenu = new Menu("Edit");
editMenu.add("Undo");
editMenu.addSeparator();
editMenu.add("Cut");
editMenu.add("Copy");
editMenu.add("Paste");
editMenu.add("Clear");
mb.add(editMenu);
}
void makeFileMenu(MenuBar mb) {
Menu fileMenu = new Menu("File");
fileMenu.add("New");
fileMenu.add("Open...");
fileMenu.addSeparator();
fileMenu.add("Close");
fileMenu.add("Save");
fileMenu.add("Save As...");
fileMenu.addSeparator();
fileMenu.add("Page Setup...");
fileMenu.add("Print");
fileMenu.addSeparator();
fileMenu.add("Quit");
mb.add(fileMenu);
}
}
<APPLET CODE="MenuPrimer.class"
WIDTH=200 HEIGHT=100>
</APPLET>
Događaji vezani uz menije
Kad korisnik odabere opciju, meni lansira objekt tipa java.awt.event.ActionEvent.
Njega može pokupiti bilo koji actionListener, dakle objekt iz klase koja
implementira interface java.awt.event.ActionListener koji smo registrovali
uz opciju, dakle objekt tipa MenuItem. Action komanda koju možemo pročitati
metodom getActionCommand() sadržaće tekst opcije.
Na primer, sledeći applet stavlja tekst odabrane opcije u tekstualno polje theChoice.
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class ActiveMenuPrimer extends Applet implements ActionListener {
TextField theChoice = new TextField(20);
public void init () {
Frame f = new Frame("Prozor i meni ");
f.add("North", new Label("Pogledajte meni ", Label.CENTER));
f.add("South", theChoice);
f.setSize(300, 200);
f.setLocation(220,240);
MenuBar myMenuBar = new MenuBar();
this.makeFileMenu(myMenuBar);
this.makeEditMenu(myMenuBar);
f.setMenuBar(myMenuBar);
f.addWindowListener(new WindowCloser());
f.show();
}
protected void addItem(Menu m, String s) {
MenuItem mi = new MenuItem(s);
mi.addActionListener(this);
m.add(mi);
}
protected void makeEditMenu(MenuBar mb) {
Menu editMenu = new Menu("Edit");
this.addItem(editMenu, "Undo");
editMenu.addSeparator();
this.addItem(editMenu, "Cut");
this.addItem(editMenu, "Copy");
this.addItem(editMenu, "Paste");
this.addItem(editMenu, "Clear");
mb.add(editMenu);
}
protected void makeFileMenu(MenuBar mb) {
Menu fileMenu = new Menu("File");
this.addItem(fileMenu, "New");
this.addItem(fileMenu, "Open...");
fileMenu.addSeparator();
this.addItem(fileMenu, "Close");
this.addItem(fileMenu, "Save");
this.addItem(fileMenu, "Save As...");
fileMenu.addSeparator();
this.addItem(fileMenu, "Page Setup...");
this.addItem(fileMenu, "Print");
fileMenu.addSeparator();
this.addItem(fileMenu, "Quit");
mb.add(fileMenu);
}
public void actionPerformed(ActionEvent e) {
theChoice.setText(e.getActionCommand());
}
class WindowCloser extends WindowAdapter {
public void windowClosing(WindowEvent e) {
Window w = (Window) e.getSource();
w.setVisible(false);
w.dispose();
}
}
}
<APPLET CODE="ActiveMenuPrimer.class" WIDTH=200 HEIGHT=100>
</APPLET>
Skraćenice menija
Skraćenice menija, poznate i pod nazivom akceleratori ili tipovni ekvivalenti
naredbe, obično ne ubrzavaju ništa, ali budući da ih korisnici vole, komercijalne
aplikacije ih poseduju.
Klasa java.awt.MenuShortcut predstavlja takve skraćenice u Javi. Poseduje sledeće konstruktore:
public MenuShortcut(int key)
public MenuShortcut(int key, boolean useShiftModifier)
U oba slučaja argument key je zapravo keycode tastera koji aktivira tu opciju.
Ako je useShiftModifier postavljen na true, onda taster shift mora biti pritisnut da bi skraćenica aktivirala opciju. Po pretpostavci, useShiftModifier je false.
Da biste opciji izbornika pridružili skraćenicu, pozovite metodu setShortcut()
iz klase java.awt.MenuItem. Na primer,
MenuShortcut pShortcut = new MenuShortcut(KeyEvent.VK_P);
MenuItem mi = new MenuItem("Print...");
mi.setShortcut(pShortcut);
Skraćenicu možete definisati i pomoću odgovarajućeg konstruktora MenuItem()
ovako:
MenuShortcut pShortcut = new MenuShortcut(KeyEvent.VK_P);
MenuItem mi = new MenuItem("Print...", pShortcut);
Skraćenicu možete ukloniti pomoću metode deleteShortcut() iz klase java.awt.MenuItem,
na primer:
mi.deleteShortcut();
Padajući meniji (Popup Menus)
Već smo se susreli s klasom java.awt.Choice čiji se objekti ponašaju
kao padajući meniji, no imaju fiksnu lokaciju.
Klasa java.awt.PopupMenu je podklasa od java.awt.Menu. Uglavnom je koristite kao i obične menije. Stavke se dodaju metodom add(), a na korisnikove izbore odgovara se pomoću ActionListenera instaliranog na MenuItem. Na primer, da biste napravili padajući meni sa različitim URL-ovima, možete postupiti ovako:
PopupMenu pm = new PopupMenu();
MenuItem mi = new MenuItem("http://www.javasoft.com/");
mi.addActionListener(URLActionListener);
pm.add(mi);
mi = new MenuItem("http://home.netscape.com/");
mi.addActionListener(URLActionListener);
pm.add(mi);
mi = new MenuItem("http://metalab.unc.edu/javafaq");
mi.addActionListener(URLActionListener);
pm.add(mi);
mi = new MenuItem("http://www.google.com");
mi.addActionListener(URLActionListener);
pm.add(mi);
Međutim, padajući meniji ne pripadaju nekom određenom MenuBaru. Umesto
toga, oni se dodaju komponenti. Na primer, za dati okvir, Frame f, instalirali
biste PopupMenu pm u taj okvir tako da ga prosledite metodi add() iz klase
java.awt.Component, ovako:
f.add(pm);
Primetite da to nije ona ista add() metoda koju koristite za dodavanje komponente okviru.
Tačan način pokretanja padajućih menija zavisi od platforme. Na primer, na Windowsima se PopupMenu pokreće podizanjem desnog tastera miša. Na Motifu se pokreće pritiskanjem desnog tastera miša. Nezavisno od sekvence događaja koja pokreće padajući meni, kad korisnik odabere neku opciju, odnosno kad odabere neki MenuItem, lansira se ActionEvent kog treba da uhvatiti odgovarajući listener registrovan uz tu stavku.
Objekt tipa PopupMenu se može ukloniti iz komponente tako da se prosledi komponentinoj metodi remove(), na primer ovako:
f.remove(pm);
Uz jednu komponentu može biti instaliran najviše jedan padajući meni.
Ako je instaliran uz kontejner, onda će trigeri iz komponenata koje se
nalaze u tom kontejneru takođe pokretati padajuće menije pod uslovom da
kontejner nema svoj vlastiti padajući meni.