Fortsetzung von letzter Seite
Buttons
Bis jetzt konnte der Benutzer recht wenig machen, er konnte sich Schrift,
Linien und Rechtecke ansehen. Am Ende konnte er das Fenster auch noch
schließen, er konnte jedoch keine Aktionen durchführen. Damit
der Benutzer auch mal was machen kann, bekommt unser Programm nun einen
Button.
Natürlich kommt der Button nicht von selbst, man muss ihn erst
einmal auf dem Frame hinzufügen. Dafür gibt es die add-Methode
des Frames. Jetzt hätten wir aber wieder das gleiche Problem wie
beim Schließen-Button beim Frame. Es passiert nichts! Also machen
wir es doch so wie beim Frame: Wird setzen einen Listener ein! Diesmal
jedoch nicht den WindowListener, sondern den ActionListener.
Dieser ist praktisch genauso aufgebaut wie der WindowListener:
addActionListener(ActionListener);
Wie schon beim WindowListener braucht die Methode ein Objekt
des Interfaces ActionListener. Dieses Interface bietet als
einzige Methode actionPerformed an.
Wir schauen uns also wieder den Quelltext zum besseren Verständnis
an:
import java.awt.*;
public class Fenster6 extends Frame { private Button btnBeenden = new Button("Beenden"); private MyWindowListener myWindowListener = new MyWindowListener(); private MyActionListener myActionListener = new MyActionListener();
public Fenster6() { super("Unser sechstes Fenster..."); this.setSize(400,100); this.add(this.btnBeenden); this.show(); this.addWindowListener(myWindowListener); this.btnBeenden.addActionListener(myActionListener); }
public static void main(String args[]) { Fenster6 f = new Fenster6(); } }
MyWindowListener.java
import java.awt.event.*;
public class MyWindowListener extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }
MyActionListener.java
import java.awt.event.*;
public class MyActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { System.exit(0); } }
In der Klasse MyActionListener sollte einem
ein ungewöhnliches Schlüsselwort auffallen: implements. implements ist das Gegenstück der Interfaces zum extends der Klassen bei der Vererbung.
Wenn du das Programm ausführst, entdeckt man jedoch schon das nächste
Problem:
Der Button füllt das ganze Fenster aus! Diesem Problem
wollen wir uns nun widmen!
Layout-Manager
Wir haben gerade selbst gesehen was passiert wenn man keine absolute
Positionierung (mit Pixelangaben) macht. Der Button füllt den ganzen
Frame aus. Aber mal zugegeben, willst du bei jedem Button immer herum
probieren wie groß er sein soll und die Pixelangaben dann ändern
und jedes Mal auch noch langwierig kompilieren? Das ist schon ganz schön
umständlich mit den Pixeln! Aber so ein ganzes Frame für nur
einen Button ist reinste Verschwendung.
Aber wie immer gibt es in Java auch dafür eine komfortable Lösung:
die Layout-Manager. Die Layout-Manager wenden Regeln zur Positionierung
und Dimensionierung der Buttons an. Im Package awt gibt es zwar 5 Layout-Manager,
ich möchte davon jedoch nur die drei wichtigsten behandeln. Und
zwar FlowLayout, BorderLayout und GridLayout.
FlowLayout
Dieser Layout-Manager ordnet die Komponenten in Zeilen von links nach
rechts an. Wenn eine Zeile voll ist, wird die nächste Komponente
in der nächsten Zeile darunter angeordnet. FlowLayout setzt die Größe der Komponenten auf ein Minimum. Der FlowLayout-Manager
hat folgenden Konstruktor: FlowLayout(int ausrichtung, int horizAbstand,
int vertAbstand)
Wobei eigentlich sämtliche Parameter optional sind. Wenn nämlich
nichts angegeben ist, werden die Komponenten zentriert angeordnet und
die Abstände sowohl horizontal als auch vertikal auf 5 Pixel gesetzt.
Abstände werden verständlicherweise in Pixel angegeben, bei
der Ausrichtung gibt es folgende Wahlmöglichkeiten bestehend aus
statischen Konstanten: FlowLayout.LEFT, FlowLayout.RIGHT und FlowLayout.CENTER
Ich habe mal folgenden Quelltext zur Verdeutlichung anzubieten:
import java.awt.*;
public class Fenster7 extends Frame { private FlowLayout myLayout = new FlowLayout(FlowLayout.LEFT); private MyWindowListener myWindowListener = new MyWindowListener(); private MyActionListener myActionListener = new MyActionListener(); private Button btn1 = new Button("1"); private Button btn2 = new Button("2"); private Button btn3 = new Button("3"); private Button btn4 = new Button("4");
public Fenster7() { super("Unser siebentes Fenster..."); this.setLayout(myLayout); this.setSize(200,100); this.add(this.btn1); this.add(this.btn2); this.add(this.btn3); this.add(this.btn4); this.show(); this.addWindowListener(this.myWindowListener); this.btn1.addActionListener(this.myActionListener); this.btn2.addActionListener(this.myActionListener); this.btn3.addActionListener(this.myActionListener); this.btn4.addActionListener(this.myActionListener); }
public static void main(String args[]) { Fenster7 f = new Fenster7(); } }
MyWindowListener.java
import java.awt.event.*;
public class MyWindowListener extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }
MyActionListener.java
import java.awt.event.*;
public class MyActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { int wert = integer.parseInt(e.getActionCommand()); switch(wert) { case 1: System.out.println("Button 1"); break; case 2: System.out.println("Button 2"); break; case 3: System.out.println("Button 3"); break; case 4: System.out.println("Button 4"); break; } } }
In der main-Methode wird nur das Fenster erzeugt,
das Aussehen wird im Konstruktor festgelegt. Der Aufruf des Layout-Managers
funktioniert mit setLayout. Erst danach werden die einzelnen
Komponenten dem Frame-Container hinzugefügt.
Da alle Buttons mit dem gleichen ActionListener-Objekt verbunden
sind, muss man in der MyActionListener-Klasse eine Unterscheidung
mittels einer switch-Auswahlabfrage durchführen. Die dafür
nötigen Daten liefert das ActionEvent-Objekt aus der actionPerformed-Methode.
Erst danach steht fest welcher Button der Auslöser war.
Jede grafische Komponente hat ein Attribut mit dem Namen actionCommand,
wenn keine Änderung daran vorgenommen wurde stimmt dieses Attribut
mit der Beschriftung überein. So können wir mit der Anweisung getActionCommand, dieses Attribut aus dem Auslöser auslesen.
Nach einer Umwandlung des Strings in einen Integerwert kann man ihn
als Selektor einsetzen.
Der Frame sieht so aus:
BorderLayout
Das BorderLayout orientiert sich an den Rändern, die durch
die Himmelsrichtungen bezeichnet werden. Aber natürlich gibt es
auch eine Mitte. Mit dem BorderLayout lassen sich maximal fünf
Komponenten platzieren.
Das BorderLayout passt die Komponentengröße der
Framegröße an. Die BorderLayout-Anweisung ist folgendermaßen
aufgebaut: BorderLayout(int horizAbstand, int vertAbstand)
Die Abstände sind wieder optional, wird also nichts angegeben,
wählt der Compiler automatisch den Abstand 0 Pixel. Es wird also
kein Abstand gelassen, wer dies verhindern will, der muss die Abstände
angeben. Da die Position der Komponente angegeben werden muss, ist es
nötig die add-Methode anzupassen. Sie muss nun so aussehen:
add(Component komponentennamen, int pos)
In der Praxis müsste die Anweisung also so aussehen: this.add(myButton, BorderLayout.CENTER). Hier sieht man schon
eine der Positionsangaben im Einsatz; die anderen sehen so aus: BorderLayout.EAST, WEST, NORTH, SOUTH
Ich möchte diesmal nur die Quellcodedatei angeben, die sich gegenüber
dem FlowLayout auch geändert hat. Wer das Beispiel nachvollziehen
will, muss einfach noch die Dateien MyWindowListener.java und MyActionListener.java aus dem vorherigen Beispiel abschreiben
(oder in den Workspace einbinden). Hier aber nun der Quelltext:
import java.awt.*;
public class Fenster8 extends Frame { private BorderLayout borderLayout = new BorderLayout(); private MyWindowListener myWindowListener = new MyWindowListener(); private MyActionListener myActionListener = new MyActionListener(); private Button btnNorth = new Button("1"); private Button btnSouth = new Button("2"); private Button btnEast = new Button("3"); private Button btnWest = new Button("4");
public Fenster8() { super("Unser achtes Fenster..."); this.setLayout(borderLayout); this.setSize(300,300); this.add(btnNorth, BorderLayout.NORTH); this.add(btnSouth, BorderLayout.SOUTH); this.add(btnEast, BorderLayout.EAST); this.add(btnWest, BorderLayout.WEST); this.show(); this.addWindowListener(this.myWindowListener); this.btnNorth.addActionListener(this.myActionListener); this.btnSouth.addActionListener(this.myActionListener); this.btnEast.addActionListener(this.myActionListener); this.btnWest.addActionListener(this.myActionListener); }
public static void main(String args[]) { Fenster8 f = new Fenster8(); } }
So sieht das BorderLayout aus:
GridLayout
Das GridLayout ordnet die Komponenten in Spalte von links nach
rechts und die Zeilen von oben nach unten. Der Konstruktor ist folgendermaßen
aufgebaut: GridLayout(int zeilen, int spalten, int hAbstand, int
vAbstand)
Die Abstände sind wieder optional. Wenn man ENTWEDER für zeilen ODER für spalten als Wert '0' eingibt, so werden
die Spalten oder Zeilen beliebig gefüllt. Es ist jedoch wichtig,
dass immer nur einer der Parameter '0' als Wert hat.
Der Hauptquelltext sieht so aus:
import java.awt.*;
public class Fenster9 extends Frame { private GridLayout myGridLayout = new GridLayout(2,0); private MyWindowListener myWindowListener = new MyWindowListener(); private MyActionListener myActionListener = new MyActionListener(); private Button btn1 = new Button("1"); private Button btn2 = new Button("2"); private Button btn3 = new Button("3"); private Button btn4 = new Button("4");
public Fenster9() { super("Unser neuntes Fenster..."); this.setLayout(borderLayout); this.setSize(300,300); this.add(this.btn1); this.add(this.btn2); this.add(this.btn3); this.add(this.btn4); this.show(); this.addWindowListener(this.myWindowListener); this.btn1.addActionListener(this.myActionListener); this.btn2.addActionListener(this.myActionListener); this.btn3.addActionListener(this.myActionListener); this.btn4.addActionListener(this.myActionListener); }
public static void main(String args[]) { Fenster9 f = new Fenster9(); } }
Unser GridLayout-Fenster sieht dann so aus:
Panels
Was ist die logische Konsequenz aus allen drei vorherigen Layout-Managern:
Am besten wäre es, wenn man sie kombinieren könnte! Ja, und
genau das wollen wir nun tun. Mit Panels lassen sich die vorherigen
Layout-Manager kombinieren um ein individuelles Layout zu entwerfen.
Ein Panel dient als Container-Objekt und ist selbst eine Komponente.
So lassen sich mehrere Panels auf dem Frame wie Komponenten
anordnen, bei dem jedoch jedes Panel seinen eigenen Layoutmanager
hat. Der Panel-Konstruktor sieht so aus:
Panel(LayoutManager layout)
Aber erst wenn man den Haupt-Quelltext gesehen hat, sieht
man wie Panels wirklich arbeiten:
import java.awt.*;
public class Panel1 extends Frame { private MyWindowListener myWindowListener = new MyWindowListener(); private MyActionListener myActionListener = new MyActionListener(); private Button btn1 = new Button("1"); private Button btn2 = new Button("2"); private Button btn3 = new Button("3"); private Button btn4 = new Button("4"); private Button btn5 = new Button("5"); private Button btn6 = new Button("6"); private Panel pnlNorth = new Panel(new BorderLayout()); private Panel pnlCenter = new Panel(new GridLayout(1,2)); private Panel pnlSouth = new Panel(new FlowLayout(FlowLayout.RIGHT));
public Panel1() { super("Unser Panel-Fenster..."); this.setSize(300,300); this.pnlNorth.add(btn1, BorderLayout.WEST); this.pnlNorth.add(btn2, BorderLayout.EAST); this.pnlCenter.add(btn3); this.pnlCenter.add(btn4); this.pnlSouth.add(btn5); this.pnlSouth.add(btn6); this.add(pnlNorth, BorderLayout.NORTH); this.add(pnlCenter, BorderLayout.CENTER); this.add(pnlSouth, BorderLayout.SOUTH); this.show(); this.addWindowListener(this.myWindowListener); this.btn1.addActionListener(this.myActionListener); this.btn2.addActionListener(this.myActionListener); this.btn3.addActionListener(this.myActionListener); this.btn4.addActionListener(this.myActionListener); }
public static void main(String args[]) { Panel1 p = new Panel1(); } }
Ein Bild des Frames zeigt wie unsere Panels aussehen:
Wir erzeugen drei Panels die wir mittels BorderLayout übereinander anordnen. Im ersten Panel erzeugen wir ein BorderLayout,
im zweiten ein GridLayout und im letzten ein FlowLayout.
Schon ist unser Panel-Fenster fertig. Sieht doch gar nicht so
schlecht aus!
Weiter auf der nächsten Seite
|