Kapitel 10 Tag 9: Grafische Benutzeroberflächen In Java gibt es zunächst zwei verschiedene Möglichkeiten Klassen für die Grafikausgabe zu verwenden. Eine Möglichkeit ist AWT (=Abstrakt Windows Toolkit) und die andere ist Swing. Die Erzeugung von Fenstern ist in beiden Varianten zunächst sehr ähnlich, aber spätenstens beim Füllen der Fensterflächen unterschieden sich beide sehr. Wir werden in den folgenden Abschnitten AWT näher besprechen. 10.1 Fenstermanagment unter AWT 10.1.1 Ein Fenster erzeugen Wir können schon mit wenigen Zeilen ein Fenster erzeugen, indem wir die Klasse Frame im package java.awt verwenden. 1 import j a v a. awt. Frame ; 2 p u b l i c c l a s s M e i n E r s t e s F e n s t e r { 3 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 4 / / ö f f n e t e i n AWT F e n s t e r 5 Frame f = new Frame ("So einfach geht das?" ) ; 6 f. s e t S i z e ( 3 0 0, 2 0 0 ) ; 7 f. s e t V i s i b l e ( true ) ; 8 9 / / L e i d e r l ä s s t es s i c h noch n i c h t s c h l i e s s e n : ), a b e r STRG+C 10 / / b e e n d e t d i e Anwendung und s c h l i e s s t das F e n s t e r... 11 } 12 } Unser Programm liefert folgende Ausgabe: Nach der Erzeugung des Fensters ist die Ausgabeposition die linke obere Ecke des Bildschirms. 105
106 KAPITEL 10. TAG 9: GRAFISCHE BENUTZEROBERFLÄCHEN 10.1.2 Das Fenster zentrieren Um das Fenster nun zu zentrieren, lesen wir zunächst die Bildschirmgrösse ein und setzen dann die Koordinaten des Fensters entsprechend. 2 p u b l i c c l a s s F e n s t e r P o s i t i o n i e r e n extends Frame { 3 p u b l i c F e n s t e r P o s i t i o n i e r e n ( i n t x, i n t y ) { 4 s e t T i t l e ("Ab in die Mitte!" ) ; 5 s e t S i z e ( x, y ) ; 6 Dimension d = T o o l k i t. g e t D e f a u l t T o o l k i t ( ). g e t S c r e e n S i z e ( ) ; 7 s e t L o c a t i o n ( ( d. width g e t S i z e ( ). width ) / 2, 8 ( d. h e i g h t g e t S i z e ( ). h e i g h t ) / 2 ) ; 9 s e t V i s i b l e ( true ) ; 10 } 11 12 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 13 F e n s t e r P o s i t i o n i e r e n f = new F e n s t e r P o s i t i o n i e r e n ( 2 0 0, 1 0 0 ) ; 14 } 15 } Nun wird das Fenster in der Mitte positioniert. 10.1.3 Zeichenfunktionen innerhalb des Fensters verwenden AWT bietet eine Reihe von Zeichenfunktionen an. Alle mit ihren Feinheiten zu beschreiben würde wieder ein ganzes Buch füllen. Wir wollen an dieser Stelle nur ein paar grundlegende Beispiele erläutern und den Leser motivieren, spätestens hier die Java API [29] als Hilfsmittel zu verwenden. 10.1.3.1 Textausgaben Wir wollen mit dem einfachen Beispiel beginnen, einen Text innerhalb des Fensterbereichs auszugeben. Zusätzlich zeigen wir in diesem Beispiel, wie sich die Farben des Vorder- und Hintergrunds verändern lassen.
10.1. FENSTERMANAGMENT UNTER AWT 107 2 p u b l i c c l a s s T e x t F e n s t e r extends Frame { 3 p u b l i c T e x t F e n s t e r ( S t r i n g t i t e l ) { 4 s e t T i t l e ( t i t e l ) ; 5 s e t S i z e ( 5 0 0, 3 0 0 ) ; 6 s e t B a c k g r o u n d ( Color. l i g h t G r a y ) ; 7 s e t F o r e g r o u n d ( Color. r e d ) ; 8 s e t V i s i b l e ( true ) ; 9 } 10 11 p u b l i c void p a i n t ( G r a p h i c s g ) { 12 g. d r a w S t r i n g ("Was soll ich nur schreiben?", 120, 60 ) ; 13 } 14 15 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 16 T e x t F e n s t e r t = new T e x t F e n s t e r ("Text im Fenster" ) ; 17 } 18 } 10.1.3.2 Zeichenelemente Exemplarisch zeigt dieses Beispiel die Verwendung der Zeichenfunktionen: drawrect und drawline. Auch hier haben wir eine zusätzliche Funktionalität eingebaut, die Wartefunktion. 2 p u b l i c c l a s s T e x t F e n s t e r 2 extends Frame { 3 p u b l i c T e x t F e n s t e r 2 ( S t r i n g t i t e l ) { 4 s e t T i t l e ( t i t e l ) ; 5 s e t S i z e ( 5 0 0, 3 0 0 ) ; 6 s e t B a c k g r o u n d ( Color. l i g h t G r a y ) ; 7 s e t F o r e g r o u n d ( Color. r e d ) ; 8 s e t V i s i b l e ( true ) ; 9 } 10 11 p u b l i c s t a t i c void wartemal ( long m i l l i s ) { 12 t r y { 13 Thread. s l e e p ( m i l l i s ) ; 14 } catch ( I n t e r r u p t e d E x c e p t i o n e ) { } 15 } 16 17 p u b l i c void p a i n t ( G r a p h i c s g ) { 18 g. drawrect ( 3 0, 5 0, 4 4 0, 2 0 0 ) ; 19 g. s e t C o l o r ( Color. b l a c k ) ; 20 g. drawline ( 3 0, 1 5 0, 4 7 0, 1 5 0 ) ; 21 g. s e t F o n t ( new Font ("SansSerif", Font.BOLD, 2 0 ) ) ;
108 KAPITEL 10. TAG 9: GRAFISCHE BENUTZEROBERFLÄCHEN 22 g. d r a w S t r i n g ("Schick!", 60, 8 0 ) ; 23 wartemal ( 3 0 0 0 ) ; 24 g. d r a w S t r i n g ("Geht so...", 350, 2 2 0 ) ; 25 } 26 27 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 28 T e x t F e n s t e r 2 t = new T e x t F e n s t e r 2 ("Text im Fenster" ) ; 29 } 30 } Unser Programmcode liefert nach der Ausführung folgende Ausgabe...... und ca. 3 Sekunden später...... eine weitere verzögerte zusätzliche Ausgabe. 10.1.3.3 Die Klasse Color verwenden Für grafische Benutzeroberflächen sind Farben sehr wichtig. Um das RGB-Farbmodell zu verwenden, erzeugen wir viele farbige Rechtecke, deren 3 Farbkomponenten rot, grün und blau zufällig gesetzt werden. Dazu erzeugen wir ein Color-Objekt und setzen diese Farbwerte. 2 import j a v a. u t i l. Random ; 3 4 p u b l i c c l a s s T e x t F e n s t e r 3 extends Frame { 5 p u b l i c T e x t F e n s t e r 3 ( S t r i n g t i t e l ) { 6 s e t T i t l e ( t i t e l ) ; 7 s e t S i z e ( 5 0 0, 3 0 0 ) ;
10.1. FENSTERMANAGMENT UNTER AWT 109 8 s e t B a c k g r o u n d ( Color. l i g h t G r a y ) ; 9 s e t F o r e g r o u n d ( Color. r e d ) ; 10 s e t V i s i b l e ( true ) ; 11 } 12 13 p u b l i c s t a t i c void wartemal ( long m i l l i s ) { 14 t r y { 15 Thread. s l e e p ( m i l l i s ) ; 16 } catch ( I n t e r r u p t e d E x c e p t i o n e ) { } 17 } 18 19 p u b l i c void p a i n t ( G r a p h i c s g ) { 20 Random r = new Random ( ) ; 21 g. c l e a r R e c t ( 0, 0, getwidth () 1, g e t H e i g h t ( ) 1 ) ; 22 23 f o r ( i n t y =30; y< g e t H e i g h t () 10; y += 15) 24 f o r ( i n t x =12; x< getwidth () 10; x += 15) { 25 g. s e t C o l o r ( new Color ( r. n e x t I n t ( 2 5 6 ), 26 r. n e x t I n t ( 2 5 6 ), 27 r. n e x t I n t ( 2 5 6 ) ) ) ; 28 g. f i l l R e c t ( x, y, 10, 10 ) ; 29 g. s e t C o l o r ( Color.BLACK ) ; 30 g. drawrect ( x 1, y 1, 10, 1 0 ) ; 31 } 32 } 33 34 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 35 T e x t F e n s t e r 3 t = new T e x t F e n s t e r 3 ("Farbe im Fenster" ) ; 36 } 37 } 10.1.3.4 Bilder laden und anzeigen Mit der Methode drawimage können wir Bilder anzeigen lassen. In den Zeilen 20 und 21 geschieht aber leider nicht das, was wir erwarten würden. Die Funktion getimage bereitet das Laden des Bildes nur vor. Der eigentliche Ladevorgang erfolgt erst beim Aufruf von drawimage. Das hat zum einen den Nachteil, dass bei einer Wiederverwendung der Methode paint jedesmal das Bild neu geladen wird. 2 import j a v a. u t i l. Random ; 3 4 p u b l i c c l a s s T e x t F e n s t e r 4 extends Frame { 5 p u b l i c T e x t F e n s t e r 4 ( S t r i n g t i t e l ) { 6 s e t T i t l e ( t i t e l ) ; 7 s e t S i z e ( 5 0 0, 3 0 0 ) ;
110 KAPITEL 10. TAG 9: GRAFISCHE BENUTZEROBERFLÄCHEN 8 s e t B a c k g r o u n d ( Color. l i g h t G r a y ) ; 9 s e t F o r e g r o u n d ( Color. r e d ) ; 10 s e t V i s i b l e ( true ) ; 11 } 12 13 p u b l i c s t a t i c void wartemal ( long m i l l i s ) { 14 t r y { 15 Thread. s l e e p ( m i l l i s ) ; 16 } catch ( I n t e r r u p t e d E x c e p t i o n e ) { } 17 } 18 19 p u b l i c void p a i n t ( G r a p h i c s g ) { 20 Image p i c = T o o l k i t. g e t D e f a u l t T o o l k i t ( ). getimage ("C:\\maja.jpg" ) ; 21 g. drawimage ( pic, 20, 20, t h i s ) ; 22 } 23 24 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 25 T e x t F e n s t e r 4 t = new T e x t F e n s t e r 4 ("Text im Fenster" ) ; 26 } 27 } Wir können aber mit Hilfe der Klasse Mediatracker die Bilder vor der eigentlichen Anzeige in den Speicher laden. Dazu verwenden wir folgende Zeilen beispielsweise im Konstruktor: 1 Image img ; 2... 3 img = g e t T o o l k i t ( ). getimage ("c:\\maja.jpg" ) ; 4 M e d i a t r a c k e r mt = new M e d i a t r a c k e r ( t h i s ) ; 5 mt. addimage ( img, 0 ) ; 6 t r y { 7 mt. w a i t F o r A l l ( ) ; 8 } catch ( I n t e r r u p t e d E x c e p t i o n e ) { } 9... 10 g. drawimage ( img, 20, 20, t h i s ) ; 10.1.4 Fenster- und Mausereignisse behandeln Als Standardfensterklasse werden wir in den folgenden Abschnitten immer von dieser erben: 1 / K l a s s e : M e i n F e n s t e r 2 S t a n d a r d f e n s t e r, d a s s z e n t r i e r t e r z e u g t ( a b e r 3 noch n i c h t a n g e z e i g t ) wird. 4 /
10.1. FENSTERMANAGMENT UNTER AWT 111 5 import j a v a. awt. ; 6 7 p u b l i c c l a s s M e i n F e n s t e r extends Frame { 8 p u b l i c M e i n F e n s t e r ( S t r i n g t i t e l, i n t w, i n t h ) { 9 t h i s. s e t T i t l e ( t i t e l ) ; 10 t h i s. s e t S i z e (w, h ) ; 11 12 / / z e n t r i e r e das F e n s t e r 13 Dimension d = T o o l k i t. g e t D e f a u l t T o o l k i t ( ). g e t S c r e e n S i z e ( ) ; 14 t h i s. s e t L o c a t i o n ( ( d. width t h i s. g e t S i z e ( ). width ) / 2, 15 ( d. h e i g h t t h i s. g e t S i z e ( ). h e i g h t ) / 2 ) ; 16 } 17 } Die Klasse MeinFenster erzeugt ein auf dem Bildschirm zentriertes Fenster und kann mit einem Konstruktor und den Attributen titel, breite und hoehe erzeugt werden. 10.1.4.1 Fenster schliessen mit dem Interface WindowListener Unser folgendes Beispiel erbt zunächst von der Klasse MeinFenster und implementiert anschliessend das Interface WindowListener. In Zeile 10 fügen verknüpfen wir unsere Anwendung mit dem WindowListener und erreichen damit, dass bei Ereignissen, wie Fenster schliessen oder Fenster aktivieren Methoden aufgerufen werden, die wir implementiert haben. 1 / K l a s s e : F e n s t e r S c h l i e s s t 2 A b g e l e i t e t von M e i n F e n s t e r 3 i m p l e m e n t i e r t WindowListener 4 s c h l i e s s t F e n s t e r a u t o m a t i s c h 5 / 6 import j a v a. awt. ; 7 import j a v a. awt. e v e n t. ; 8 p u b l i c c l a s s F e n s t e r S c h l i e s s t extends M e i n F e n s t e r 9 implements WindowListener { 10 p u b l i c F e n s t e r S c h l i e s s t ( S t r i n g t i t e l, i n t w, i n t h ) { 11 super ( t i t e l, w, h ) ; 12 addwindowlistener ( t h i s ) ; / / wir r e g i s t r i e r e n h i e r den E r e i g n i s t y p 13 / / f ü r WindowEvents 14 s e t V i s i b l e ( true ) ; 15 } 16 17 / / 18 / / Hier werden d i e WindowListener Methoden i m p l e m e n t i e r t 19 / / Methode : F e n s t e r wird g e s c h l o s s e n 20 p u b l i c void windowclosing ( WindowEvent e v e n t ) { 21 System. e x i t ( 0 ) ; 22 } 23 p u b l i c void windowclosed ( WindowEvent e v e n t ) {} 24 p u b l i c void windowdeiconified ( WindowEvent e v e n t ) {} 25 p u b l i c void w i n d o w I c o n i f i e d ( WindowEvent e v e n t ) {} 26 p u b l i c void windowactivated ( WindowEvent e v e n t ) {} 27 p u b l i c void windowdeactivated ( WindowEvent e v e n t ) {} 28 p u b l i c void windowopened ( WindowEvent e v e n t ) {} 29 / / 30 31 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 32 F e n s t e r S c h l i e s s t f = new F e n s t e r S c h l i e s s t ("Schliesse mich!", 200, 1 0 0 ) ; 33 } 34 }
112 KAPITEL 10. TAG 9: GRAFISCHE BENUTZEROBERFLÄCHEN In Zeile 18 verwenden wir die Funktion System.exit(0). Es werden alle Fenster der Anwendung geschlossen und das Programm beendet. Leider haben wir mit der Implementierung des Interfaces WindowListener den Nachteil, dass wir alle Methoden implementieren müssen. Das Programm wird schnell unüberschaubar, wenn wir verschiedene Eventtypen abfangen wollen und für jedes Interface alle Methoden implementieren müssen. Hilfe verspricht die Klasse WindowAdapter, die das Interface WindowListener bereits mit leeren Funktionskörpern implementiert hat. Wir können einfach von dieser Klasse erben und eine der Methoden überschreiben. Um die restlichen brauchen wir uns nicht zu kümmern. 1 / K l a s s e : F e n s t e r S c h l i e s s t S c h i c k 2 A b g e l e i t e t von M e i n F e n s t e r 3 i m p l e m e n t i e r t WindowListener 4 s c h l i e s s t F e n s t e r a u t o m a t i s c h 5 / 6 import j a v a. awt. ; 7 import j a v a. awt. e v e n t. ; 8 p u b l i c c l a s s F e n s t e r S c h l i e s s t S c h i c k extends M e i n F e n s t e r { 9 p u b l i c F e n s t e r S c h l i e s s t S c h i c k ( S t r i n g t i t e l, i n t w, i n t h ) { 10 super ( t i t e l, w, h ) ; 11 / / Wir verwenden e i n e Klasse, d i e nur d i e gewünschten Methoden 12 / / d e r K l a s s e WindowAdapter ü b e r s c h r e i b t. 13 addwindowlistener ( new WindowClosingAdapter ( ) ) ; 14 s e t V i s i b l e ( true ) ; 15 } 16 17 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 18 F e n s t e r S c h l i e s s t S c h i c k f = 19 new F e n s t e r S c h l i e s s t S c h i c k ("Schliesse mich!", 200, 1 0 0 ) ; 20 } 21 } 22 23 / Etwas n e r v i g war es, a l l e Methoden, d i e das I n t e r f a c e WindowListener 24 a n g e b o t e n hat, ü b e r s c h r e i b e n zu müssen. Angenehmer i s t es, d i e 25 WindowAdapter K l a s s e zu verwenden. S i e h a t a l l e F u n k t i o n e n b e r e i t s 26 mit l eerem Programmkörper i m p l m e n t i e r t. Wollen wir nur e i n e F u n k t i o n 27 verwenden, so können wir i n e i n e r S u b k l a s s e von WindowAdapter d i e 28 gewünschte Methode ü b e r s c h r e i b e n. In diesem F a l l, windowclosing. 29 / 30 c l a s s WindowClosingAdapter extends WindowAdapter { 31 p u b l i c void windowclosing ( WindowEvent e ) { 32 System. e x i t ( 0 ) ; 33 } 34 } Wie können auch die Klasse WindowClosingAdapter als innere Klasse deklarieren. 2 import j a v a. awt. e v e n t. ; 3 4 p u b l i c c l a s s F e n s t e r S c h l i e s s t S c h i c k 2 extends M e i n F e n s t e r { 5 p u b l i c F e n s t e r S c h l i e s s t S c h i c k 2 ( S t r i n g t i t e l, i n t w, i n t h ) { 6 super ( t i t e l, w, h ) ; 7 addwindowlistener ( new WindowClosingAdapter ( ) ) ; 8 s e t V i s i b l e ( true ) ; 9 } 10 11 / / 12 / / i n n e r e K l a s s e 13 p r i v a t e c l a s s WindowClosingAdapter extends WindowAdapter { 14 p u b l i c void windowclosing ( WindowEvent e ) { 15 System. e x i t ( 0 ) ;
10.1. FENSTERMANAGMENT UNTER AWT 113 16 } 17 } 18 / / 19 20 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 21 F e n s t e r S c h l i e s s t S c h i c k 2 f = 22 new F e n s t e r S c h l i e s s t S c h i c k 2 ("Schliesse mich!", 200, 1 0 0 ) ; 23 } 24 } Eine noch kürzere Schreibweise könnten wir erreichen, indem wir die Klasse WindowAdapter nur lokal erzeugen und die Funktion überschreiben (wie wir es bei dem sehr übersichtlich gestalteten Galileo-Onlinebuch [15] von Christian Ullenboom erfahren können). Wir nennen solche Klassen innere, anonyme Klassen. 1 import j a v a. awt. e v e n t. ; 2 p u b l i c c l a s s F e n s t e r S c h l i e s s t S c h i c k K u r z extends M e i n F e n s t e r { 3 p u b l i c F e n s t e r S c h l i e s s t S c h i c k K u r z ( S t r i n g t i t e l, i n t w, i n t h ) { 4 super ( t i t e l, w, h ) ; 5 / / Wir verwenden e i n e i n n e r e anonyme K l a s s e. Kurz und knapp. 6 addwindowlistener ( new WindowAdapter ( ) { 7 p u b l i c void windowclosing ( WindowEvent e ) { 8 System. e x i t ( 0 ) ; 9 } 10 } ) ; 11 s e t V i s i b l e ( true ) ; 12 } 13 14 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 15 F e n s t e r S c h l i e s s t S c h i c k K u r z f = 16 new F e n s t e r S c h l i e s s t S c h i c k K u r z ("Schliesse mich!", 200, 1 0 0 ) ; 17 } 18 } Dieses Verfahren werden wir ab sofort für kleine Funktionen verwenden. Sollten die Funktionen zu gross werden, greifen wir auf die privaten Klassen zurück. 10.1.4.2 GUI-Elemente und ihre Ereignisse Wir werden uns nun exemplarisch Beispiele anschauen, bei denen GUI-Elemente erzeugt und auf Aktionen reagiert werden. Die Komponente Button 2 import j a v a. awt. e v e n t. ; 3 p u b l i c c l a s s GUI_Button extends M e i n F e n s t e r { 4 B u tton b u t t o n 1, b u t t o n 2 ; 5 Label l a b e l 1 ; 6 7 / / Im K o n s t r u k t o r e r z e u g e n wir d i e GUI Elemente 8 p u b l i c GUI_Button ( S t r i n g t i t e l, i n t w, i n t h ) { 9 super ( t i t e l, w, h ) ; 10 s e t S i z e (w, h ) ; 11 12 / / Wir r e g i s t r i e r e n den WindowListener, um a u f 13 / / WindowEvents r e a g i e r e n zu können 14 addwindowlistener ( new MeinWindowListener ( ) ) ;
114 KAPITEL 10. TAG 9: GRAFISCHE BENUTZEROBERFLÄCHEN 15 16 / / wir bauen e i n e n A c t i o n L i s t e n e r, d e r nur a u f Knopfdruck 17 / / r e a g i e r t 18 A c t i o n L i s t e n e r a k t i o n = new Knopfdruck ( ) ; 19 20 s e t L a y o u t ( new FlowLayout ( ) ) ; 21 b u t t o n 1 = new B u tton ("Linker Knopf" ) ; 22 add ( b u t t o n 1 ) ; 23 b u t t o n 1. a d d A c t i o n L i s t e n e r ( a k t i o n ) ; 24 b u t t o n 1. setactioncommand ("b1" ) ; 25 b u t t o n 2 = new B u tton ("Rechter Knopf" ) ; 26 add ( b u t t o n 2 ) ; 27 b u t t o n 2. a d d A c t i o n L i s t e n e r ( a k t i o n ) ; 28 b u t t o n 2. setactioncommand ("b2" ) ; 29 l a b e l 1 = new Label ("Ein Label" ) ; 30 add ( l a b e l 1 ) ; 31 s e t V i s i b l e ( true ) ; 32 } 33 34 / / 35 / / I n n e r e K l a s s e n f ü r das Eventmanagment 36 c l a s s MeinWindowListener extends WindowAdapter { 37 p u b l i c void windowclosing ( WindowEvent e v e n t ) { 38 System. e x i t ( 0 ) ; 39 } 40 } 41 42 c l a s s Knopfdruck implements A c t i o n L i s t e n e r { 43 p u b l i c void a c t i o n P e r f o r m e d ( A c t i o n E v e n t e ) { 44 l a b e l 1. s e t T e x t ( e. getactioncommand ( ) ) ; 45 } 46 } 47 / / 48 49 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 50 GUI_Button f = new GUI_Button ("Schliesse mich!", 500, 5 0 0 ) ; 51 } 52 }
10.1. FENSTERMANAGMENT UNTER AWT 115 Auf die Ereignisse individuell reagieren, Anzeige aber mit anderem LayoutManager: 2 import j a v a. awt. e v e n t. ; 3 4 p u b l i c c l a s s GUI_Button_Aktion extends M e i n F e n s t e r { 5 B u tton b u t t o n 1, b u t t o n 2 ; 6 Label l a b e l 1 ; 7 8 / / Im K o n s t r u k t o r e r z e u g e n wir d i e GUI Elemente 9 p u b l i c GUI_Button_Aktion ( S t r i n g t i t e l, i n t w, i n t h ) { 10 super ( t i t e l, w, h ) ; 11 s e t S i z e (w, h ) ; 12 13 / / Wir r e g i s t r i e r e n den WindowListener, um a u f 14 / / WindowEvents r e a g i e r e n zu können 15 addwindowlistener ( new MeinWindowListener ( ) ) ; 16 17 / / wir bauen e i n e n A c t i o n L i s t e n e r, d e r nur a u f Knopfdruck 18 / / r e a g i e r t 19 A c t i o n L i s t e n e r a k t i o n = new Knopfdruck ( ) ; 20 21 s e t L a y o u t ( new BorderLayout ( ) ) ; 22 23 b u t t o n 1 = new B u tton ("Linker Knopf" ) ; 24 add ( b u t t o n 1, BorderLayout.NORTH) ; 25 b u t t o n 1. a d d A c t i o n L i s t e n e r ( a k t i o n ) ; 26 b u t t o n 1. setactioncommand ("b1" ) ; 27 28 b u t t o n 2 = new B u tton ("Rechter Knopf" ) ; 29 add ( b u t t o n 2, BorderLayout.SOUTH ) ; 30 b u t t o n 2. a d d A c t i o n L i s t e n e r ( a k t i o n ) ; 31 b u t t o n 2. setactioncommand ("b2" ) ; 32 33 l a b e l 1 = new Label ("Platz für ein Label" ) ; 34 add ( l a b e l 1, BorderLayout. CENTER ) ; 35 36 s e t V i s i b l e ( true ) ; 37 } 38 39 p r i v a t e void B u t t o n 1 C l i c k e d ( ) { 40 l a b e l 1. s e t T e x t ("Button1" ) ; 41 } 42 43 p r i v a t e void B u t t o n 2 C l i c k e d ( ) { 44 l a b e l 1. s e t T e x t ("Button2" ) ; 45 } 46 / / 47 / / I n n e r e K l a s s e n f ü r das Eventmanagment 48 c l a s s MeinWindowListener extends WindowAdapter { 49 p u b l i c void windowclosing ( WindowEvent e v e n t ) { 50 System. e x i t ( 0 ) ; 51 } 52 } 53 54 c l a s s Knopfdruck implements A c t i o n L i s t e n e r { 55 p u b l i c void a c t i o n P e r f o r m e d ( A c t i o n E v e n t e ) { 56 / / wir b e h a n d e l n d i e E r e i g n i s s e 57 S t r i n g cmd = e. getactioncommand ( ) ; 58 i f ( cmd. e q u a l s ("b1" ) ) 59 B u t t o n 1 C l i c k e d ( ) ; 60 i f ( cmd. e q u a l s ("b2" ) ) 61 B u t t o n 2 C l i c k e d ( ) ;
116 KAPITEL 10. TAG 9: GRAFISCHE BENUTZEROBERFLÄCHEN 62 } 63 } 64 / / 65 66 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 67 GUI_Button_Aktion f = new GUI_Button_Aktion ("Klick mich...", 500, 5 0 0 ) ; 68 } 69 } Die Komponente TextField 2 import j a v a. awt. e v e n t. ; 3 4 p u b l i c c l a s s GUI_Button_TextField extends M e i n F e n s t e r { 5 B u tton b u t t o n 1 ; 6 Label l a b e l 1 ; 7 T e x t F i e l d t e x t f i e l d 1 ; 8 9 / / Im K o n s t r u k t o r e r z e u g e n wir d i e GUI Elemente 10 p u b l i c GUI_Button_TextField ( S t r i n g t i t e l, i n t w, i n t h ) { 11 super ( t i t e l, w, h ) ; 12 s e t S i z e (w, h ) ; 13 14 / / Wir r e g i s t r i e r e n den WindowListener, um a u f 15 / / WindowEvents r e a g i e r e n zu können 16 addwindowlistener ( new MeinWindowListener ( ) ) ; 17 18 / / wir bauen e i n e n A c t i o n L i s t e n e r, d e r nur a u f Knopfdruck 19 / / r e a g i e r t 20 A c t i o n L i s t e n e r a k t i o n = new Knopfdruck ( ) ; 21 22 s e t L a y o u t ( new FlowLayout ( ) ) ; 23 24 t e x t f i e l d 1 = new T e x t F i e l d ("hier steht schon was", 2 5 ) ; 25 add ( t e x t f i e l d 1 ) ; 26
10.1. FENSTERMANAGMENT UNTER AWT 117 27 b u t t o n 1 = new B u tton ("Knopf" ) ; 28 add ( b u t t o n 1 ) ; 29 b u t t o n 1. a d d A c t i o n L i s t e n e r ( a k t i o n ) ; 30 b u t t o n 1. setactioncommand ("b1" ) ; 31 32 l a b e l 1 = new Label ("noch steht hier nicht viel" ) ; 33 add ( l a b e l 1 ) ; 34 35 s e t V i s i b l e ( true ) ; 36 } 37 38 p r i v a t e void B u t t o n 1 C l i c k e d ( ) { 39 S t r i n g t x t = t e x t f i e l d 1. g e t T e x t ( ) ; 40 l a b e l 1. s e t T e x t ( t x t ) ; 41 } 42 43 / / 44 / / I n n e r e K l a s s e n f ü r das Eventmanagment 45 c l a s s MeinWindowListener extends WindowAdapter { 46 p u b l i c void windowclosing ( WindowEvent e v e n t ) { 47 System. e x i t ( 0 ) ; 48 } 49 } 50 51 c l a s s Knopfdruck implements A c t i o n L i s t e n e r { 52 p u b l i c void a c t i o n P e r f o r m e d ( A c t i o n E v e n t e ) { 53 / / wir b e h a n d e l n d i e E r e i g n i s s e 54 S t r i n g cmd = e. getactioncommand ( ) ; 55 i f ( cmd. e q u a l s ("b1" ) ) 56 B u t t o n 1 C l i c k e d ( ) ; 57 } 58 } 59 / / 60 61 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 62 GUI_Button_TextField f = 63 new GUI_Button_TextField ("Klick mich...", 500, 5 0 0 ) ; 64 } 65 }
118 KAPITEL 10. TAG 9: GRAFISCHE BENUTZEROBERFLÄCHEN 10.1.4.3 Auf Mausereignisse reagieren 2 import j a v a. awt. e v e n t. ; 3 p u b l i c c l a s s MausKlick extends M e i n F e n s t e r { 4 p u b l i c MausKlick ( S t r i n g t i t e l, i n t w, i n t h ) { 5 super ( t i t e l, w, h ) ; 6 / / Wir verwenden e i n e i n n e r e anonyme K l a s s e. Kurz und knapp. 7 addwindowlistener ( new WindowAdapter ( ) { 8 p u b l i c void windowclosing ( WindowEvent e ) { 9 System. e x i t ( 0 ) ; 10 } 11 } ) ; 12 a d d M o u s e L i s t e n e r ( new MouseAdapter ( ) { 13 p u b l i c void mousepressed ( MouseEvent e ) { 14 G r a p h i c s g = g e t G r a p h i c s ( ) ; 15 g. s e t C o l o r ( Color. g r e e n ) ; 16 g. f i l l O v a l ( 5 0, 5 0, 1 0, 1 0 ) ; 17 } 18 } ) ; 19 } 20 21 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 22 MausKlick f = new MausKlick ("Schliesse mich!", 200, 1 0 0 ) ; 23 } 24 } Liefert nach Klick mit der Maus, innhalb des Fensters, folgende Ausgabe: 10.2 Das Projekt Taschenrechner Mit den Erkenntnissen, die wir aus den vorhergehenden Kapiteln gewonnen haben, wollen wir nun eine erste richtige Anwendung mit AWT schreiben. Unser Ziel ist es einen Taschenrechner zu implementieren, der auf verschiedene Eingaben reagiert und Operationen auf diesen Eingaben ausführen kann.