Detta dokument förutsätter Netscape 4 eller Internet Explorer 4, om du har tidigare versioner klicka här.
(OBS! I Java JDK 1.2 finns en ny uppsättning GUI-klasser (Swing
)
som på sikt troligen kommer att ersätta AWT. Principerna behålls i denna
standard som mest
ändrar utseende och namn på existerande komponenter och lägger till en mängd
nya. Men plugga alltså inte in detaljerna i AWT eftersom de kommer att förlora
i betydelse).
Dessa klasser kan sedan delas in i olika grupper:
Graphics, Color, Cursor, Font, Image
Point, Dimension, Polygon, Rectangle
Component, MenuComponent
Button, Label, Choice, Checkbox
TextArea, TextField
MenuBar, Menu, PopupMenu
Window, Frame, Panel, ScrollPane
Canvas
List, Dialog, FileDialog
Scrollbar
...Layout
.
Ett användargränssnitt består av en behållare (Frame
i
applikationer, Panel
i applets - Applet
är en
subklass till Panel
) som andra komponenter placeras i.
Eftersom dessa komponenter i sin tur kan vara behållare (Panel
s)
kan man bygga hur komplicerade gränssnitt som helst.
Exakt hur de olika komponenterna placeras i sin behållare bestäms av
en s.k. layout-hanterare: klasserna som har namn som slutar
på ...Layout
. Man placerar alltså normalt inte komponenterna på
fasta positioner (även om detta också är möjligt) eftersom man vill att
utformningen skall vara så oberoende som möjligt av fönstersystem. Varje
behållare har en layout-hanterare kopplad till sig. Alla layout-hanterarna
implementerar gränssnittet LayoutManager
. Metoden
setLayout(LayoutManager)
i Container
används för
att koppla en layout-hanterare till en behållare - om man skulle vilja placera
ut komponenterna själv skall man anropa setLayout
med argumentet
null
.
Window
och Dialog
)
måste placeras i en behållare för att synas. Man placeras en
komponent genom att anropa någon av behållarens add
-metoder.
Vilken metod man bör använda styrs av vilken layout-hanterare man valt.
Klassen Component
har metoder för
paint(Graphics), update(Graphics),
repaint()
setForeground(Color), setBackground(Color),
Color getForeground, Color getBackground()
setFont(Font), Font getFont()
setSize(int w, int h), Dimension getSize()
setLocation(int x, int y), Point getLocation()
Klicka här för en utförligare beskrivning av AWT.
Interaktivt styrda program kan inte skrivas enligt det traditionella
sekventiella mönstret: initiera, kör algoritmen, avsluta. I stället
använder man s.k. händelsestyrd programmering. Händelser är sådant som
användaren gör, t.ex. klickar med musen, tar bort ett fönster. I AWT genererar
alla sådana händelser ett händelseobjekt som sedan tas om hand av en s.k.
lyssnare (Listener
). Klasser som har med händelser att göra
finns i paketet java.awt.event
(AWTEvent
ligger i java.awt
). De viktigaste händelserna:
Som Java-programmerare behöver man oftast inte hantera händelseobjekten - det räcker att veta att en händelse inträffat. Några undantg:
InputEvent
: int getModifiers()
ger musknapp,
shift m.m.
MouseEvent
: int getX(), int getY()
ger
pekarposition.
KeyEvent
: char getKeyChar()
ger tecknet.
ItemEvent
: Object getItem()
ger objektet som
genererade händelsen
public class MyEventHandler implements ActionListener { ... }Man kan låta händelsehanteraren vara en egen klass som här eller man kan implementera lyssnaren i någon annan klass.
MyEventHandler
måste skapas och den
komponent vars händelser man är intresserad av måste informeras om lyssnaren:
MyEventHandler oneEventHandler = new MyEventHandler(); Button b = new Button(); b.addActionListener( oneEventHandler );
MyEventHandler
:
public void actionPerformed( ActionEvent event ) { ... gör vad som ska göras }
I klassen Component
finns metoder för att hantera (lägga till
och ta bort) lyssnare:
addFocusListener(FocusListener),
removeFocusListener(KeyListener)
addKeyListener(KeyListener), removeKeyListener(KeyListener)
addMouseListener(MouseListener),
removeMouseListener(MouseListener)
addMouseMotionListener(MouseMotionListener),
removeMouseMotionListener(MouseMotionListener)
Button, MenuItem, TextField: addActionListener(ActionListener),
removeActionListener(ActionListener)
Choice, Checkbox, List: addItemListener(ItemListener),
removeItemListener(ItemListener)
TextComponent: addTextListener(TextListener),
removeTextListener(TextListener)
Window: addWindowListener(WindowListener),
removeWindowListener(WindowListener)
actionPerformed(ActionEvent)
-
en aktion (knapptryck, menyval) inträffar
focusGained(FocusEvent)
- komponenten får fokusfocusLost(FocusEvent)
- komponenten förlorar fokus
itemStateChanged(ItemEvent)
-
status har ändrats (från vald till ej vald ellervice versa)
keyPressed(KeyEvent), keyReleased(KeyEvent)
- en tangent trycks
ned eller släpps.keyTyped
- en tecken har skrivits
mouseClicked(MouseEvent), mousePressed(MouseEvent),
mouseReleased(MouseEvent)
mouseExited(MouseEvent), mouseEntered(MouseEvent)
- muspekaren
kommer in i eller lämnar en komponent
textValueChanged
- texten har ändrats
windowActivated(WindowEvent), windowClosed(WindowEvent),
windowClosing(WindowEvent), windowDeactivated(WindowEvent),
windowDeiconified(WindowEvent), windowIconified(WindowEvent),
windowOpened(WindowEvent)
Eftersom en lyssnare är ett gränssnitt måste man implementera alla metoder även om man bara är intresserad av en av dem. Vi skall snart se att det finns klasser, s.k. adaptorer, som förenklar detta åt oss.
hur
komponenterna i ett användargränssnitt läggs ut bestäms
av en s.k. layout-hanterare. Vilken man väljer beror på vad man vill uppnå.
Tänk också på att att AWT möjliggör hierarkiska GUIs: man kan t.ex. ha ett
fönster med FlowLayout
där alla eller några av komponenterna är
Panel
er, var och en med sin egen layout-hanterare. Alla behållare
har en metod setLayout( LayoutManager )
som används för att
koppla en hanterare till behållaren (LayoutManager
är ett
interface
som implementeras av layout-hanterarna).Exemplet efter de korta beskrivningarna visar hur man använder layout-hanterarna).
FlowLayout
(default för Panel
) placerar komponenterna
i en rad efter varandra eller i flera rader om utrymmet tar slut. Vid
konstruktionen av FlowLayout
- objektet kan man välja om
komponenterna skall centreras, vänsterjusteras eller högerjusteras i det
tillgängliga utrymmet.
GridLayout
placerar komponenterna i ett rutnät där alla rutor
är lika stora. Man kan specifiera antalet rader och kolumner samt avståndet
mellan rutorna.
BorderLayout
(default för Frame
) delar in
behållaren i fem områden: öster, väster, norr, söder och mitten. I varje
område kan en komponent placeras. Mittenområdet växer mest om behällaren
ändrar storlek.
CardLayout
är annorlunda än de övriga på så sätt att endast
en komponent syns samtidigt. Komponenterna ses som kort i en kortlek.
GridBagLayout
är en generalisering av GridLayout
där
de olika komponenterna placeras i rutnät med olikstora rutor: man använder
instanser av GridBagConstraints
för att specificera hur. Denna
klass är inte speciellt lättanvänd eller intuitiv, men eftersom den existerar
nämns den in alla fall här.
GridLayout
med 2x2 rutor med en
Panel
i varje ruta. Dessa i sin tur använder olika typer
av layout-hanterare.
Observera att endast tryckningar på knappar i
Card
-Panel
en tas om hand av programmet.
Koden och litet mer information om de olika hanterarna finns här.
Program får rita endast på order från systemet; annars kunde konstigheter
som att man ritar i icke-existerande fönster inträffa. Ritning fungerar
därför så att en komponent begär att få bli ritad genom att anropa
metoden repaint()
. AWT begär sedan i sin tur att komponenten
ska rita sig genom att anropa komponentens update()
-metod.
Denna metod i sin tur rensar sin rityta och anropar paint()
.
En fix komponent (som Button
) implementerar alltså hela sin
grafik i paint()
-metoden. Detta gäller de flesta komponenter
men om någonting ändras i bilden kan alltså komponenten själv anropa
repaint()
för att få möjlighet att rita om sig. I
animeringar
ersätter man också ofta update()
med en egen variant. De två
metoderna paint()
och update()
har ett argument:
en instans av ett objekt av klassen Graphics
som kan ses som
den ritmiljö man ritar i. Klassen har metoder för att rita linjer, cirklar,
ellipser, skriva text, m.m. Dessutom finns information om hur stor del av
fönstret som behöver ritas om.
Grafik kan man rita i flera av AWT-komponenterna men oftast ritar man i
instanser av Canvas
eller Applet
eller (oftare
ändå) subklasser till dessa. Det enklaste sättet att rita grafik är att helt
enkelt skriva ritinstruktionerna i paint()
.
Appleten som följer ritar de figurer som klassen Graphics
definierar. Det finns också metoder för att rita bilder.
Koden finns här.
java.awt.Color
definierar vilken färg man
ritar med. Klassen innehåller dels några konstanter för de vanligaste färgerna,
dels också några metoder för att manipulera en färg:
brighter()
, darker()
.Man kan också skapa egna färger med konstruktorn:
Color( int redvalue, int greenvalue, int bluevalue); //Exempel, skapa en gråröd färg: Color mycolor = new Color( 200, 100, 100); //Exempel, använd röd färg: g.setColor( Color.red ); // Använd den fördefinierade konstantendär färgvärdena skall ligga i intervallet 0 till 255 där 255 har högst intensitet.
java.awt.Font
inkapslar typsnittshantering i Java-grafik.
Dess enda konstruktor är:
Font(String name, int style,int size) // Exempel: Font myfont = new Font( "Times", Font.BOLD, 12 );
style
skall vara en av Font.BOLD, Font.ITALIC
eller
Font.PLAIN
. Den första parametern anger typsnittsfamilj i form av
en sträng: vilka typsnitt som finns är plattformsberoende.
För att minska skrivarbetet finns några s.k. adaptorer, tomma implementationer av lyssnargränssitten, definierade. I stället för att implementera ett gränssnitt kan man skapa en subklass till en adaptor:
import java.applet.*; import java.awt.*; import java.awt.event.*; public class Scribble extends Applet { private int x; private int y; MyMouseAdapter mma; MyMouseMotionAdapter mmma; private Color stringToColor ( String colstring ) { if (colstring.equals("red")) return Color.red; else if (colstring.equals("green")) return Color.green; else if (colstring.equals("blue") )return Color.blue; else if (colstring.equals("yellow")) return Color.yellow; else return Color.white; } public void init() { setBackground( stringToColor( getParameter("colour")) ); mma = new MyMouseAdapter(); mmma = new MyMouseMotionAdapter(); addMouseListener( mma ); addMouseMotionListener( mmma ); } public class MyMouseAdapter extends MouseAdapter { public void mousePressed( MouseEvent e ) { x = e.getX(); y = e.getY(); } } public class MyMouseMotionAdapter extends MouseMotionAdapter { public void mouseDragged( MouseEvent e ) { Graphics g = getGraphics(); g.drawLine( x, y, e.getX(), e.getY() ); x = e.getX(); y = e.getY(); } } }
Flera av de exempel vi sett har nästlade eller
inre klasser, d.v.s.klasser som helt definieras inne i
andra klasser. Ett exempel är de två adaptorerna i Scribble
.
Eftersom en Javaklass inte kan ärva mer än en klass kan man inte ärva
både Applet
och en adaptor utan man får ta till en
inre klass.
En inre klass är ett specialfall av en nästlad klass, nämligen en icke statisk nästlad klass. Inre klasser kan komma åt den omgivande klassens metoder och attribut. En instans av en inre klass kan finnas och fungera bara inuti en instans av sin omgivande klass.
MyMouseAdapter
och MyMouseMotionAdapter
i exemplet Scribble
har som enda uppgift att implementera
händelsehanteringen. Själva namnen är ointressanta och faktum är att Java
tillåter icke namngivna inre klasser, s.k. anonyma klasser. Vi skulle
kunna förenkla Scribble
:
import java.applet.*; import java.awt.*; import java.awt.event.*; public class ScribbleAnonymous extends Applet { private int x; private int y; public void init() { setBackground( Color.yellow ); addMouseListener( new MouseAdapter() { public void mousePressed( MouseEvent e ) { x = e.getX(); y = e.getY(); } } ); addMouseMotionListener( new MouseMotionAdapter() { public void mouseDragged( MouseEvent e ) { Graphics g = getGraphics(); g.drawLine(x,y,e.getX(),e.getY()); x = e.getX(); y = e.getY(); } } ); } }Ett överdrivet användande av inre och speciellt anonyma klasser gör koden klart oläsbar varför man bör vara sparsam med dem: anonyma klasser bör ha en eller högst två metoder och vara av typen "klass som gör en enda sak" (som adaptorerna).