|
In vielen grafischen Oberflächen wird die Anordnung der Elemente eines Dialoges durch Angabe absoluter Koordinaten vorgenommen. Dabei wird für jede Komponente manuell oder mit Hilfe eines Ressourcen-Editors pixelgenau festgelegt, an welcher Stelle im Dialog sie zu erscheinen hat.
Da Java-Programme auf vielen unterschiedlichen Plattformen mit unterschiedlichen Ausgabegeräten laufen sollen, war eine solche Vorgehensweise für die Designer des AWT nicht akzeptabel. Sie wählten statt dessen den Umweg über einen Layoutmanager, der für die Anordnung der Dialogelemente verantwortlich ist. Um einen Layoutmanager verwenden zu können, wird dieser dem Fenster vor der Übergabe der Dialogelemente mit der Methode setLayout zugeordnet. Er ordnet dann die per add übergebenen Elemente auf dem Fenster an.
Jeder Layoutmanager implementiert seine eigene Logik bezüglich der optimalen Anordnung der Komponenten:
Neben den gestalterischen Fähigkeiten eines Layoutmanagers bestimmt in der Regel die Reihenfolge der Aufrufe der add-Methode des Fensters die tatsächliche Anordnung der Komponenten auf dem Bildschirm. Wenn nicht - wie es z.B. beim BorderLayout möglich ist - zusätzliche Positionierungsinformationen an das Fenster übergeben werden, ordnet der jeweilige Layoutmanager die Komponenten in der Reihenfolge ihres Eintreffens an.
Um komplexere Layouts realisieren zu können, als die Layoutmanager sie in ihren jeweiligen Grundausprägungen bieten, gibt es die Möglichkeit, Layoutmanager zu schachteln. Auf diese Weise kann auch ohne Vorgabe fester Koordinaten fast jede gewünschte Komponentenanordnung realisiert werden. Sollte auch diese Variante nicht genau genug sein, so bietet sich schließlich durch Verwendung eines Null-Layouts die Möglichkeit an, Komponenten durch Vorgabe fester Koordinaten zu plazieren.
Die Klasse FlowLayout stellt den einfachsten Layoutmanager dar. Alle Elemente werden so lange nacheinander in einer Zeile angeordnet, bis kein Platz mehr vorhanden ist und in der nächsten Zeile fortgefahren wird.
Das FlowLayout
wird einem Fenster durch folgende Anweisung zugeordnet:
setLayout(new FlowLayout());
Neben dem parameterlosen gibt es weitere Konstruktoren, die die Möglichkeit bieten, die Anordnung der Elemente und ihre Abstände voneinander vorzugeben:
public FlowLayout(int align) public FlowLayout(int align, int hgap, int vgap) |
java.awt.FlowLayout |
Der Parameter align gibt an, ob die Elemente einer Zeile linksbündig, rechtsbündig oder zentriert angeordnet werden. Hierzu stehen die Konstanten FlowLayout.CENTER, FlowLayout.LEFT und FlowLayout.RIGHT zur Verfügung, als Voreinstellung wird FlowLayout.CENTER verwendet. Mit hgap und vgap können die horizontalen und vertikalen Abstände zwischen den Komponenten vorgegeben werden. Die Voreinstellung ist 5.
Das folgende Listing zeigt die Verwendung der Klasse FlowLayout am Beispiel von fünf Buttons, die in einem Grafikfenster angezeigt werden. Anstelle der normalen zentrierten Anordnung werden die Elemente linksbündig angeordnet, und der Abstand zwischen den Buttons beträgt 20 Pixel:
|
![]() |
|
![]() |
Das Programm erzeugt folgendes Fenster:
Abbildung 21.2: Verwendung der Klasse FlowLayout
Ein GridLayout bietet eine größere Kontrolle über die Anordnung der Elemente als ein FlowLayout. Hier werden die Komponenten nicht einfach nacheinander auf dem Bildschirm positioniert, sondern innerhalb eines rechteckigen Gitters angeordnet, dessen Elemente eine feste Größe haben.
Das Programm übergibt dazu beim Aufruf des Konstruktors zwei Parameter, rows und columns, mit denen die vertikale und horizontale Anzahl an Elementen festgelegt wird:
public void GridLayout(int rows, int columns) |
java.awt.GridLayout |
Beim Aufruf von add werden die Komponenten dann nacheinander in die einzelnen Zellen der Gittermatrix gelegt. Analog zum FlowLayout wird dabei zunächst die erste Zeile von links nach rechts gefüllt, dann die zweite usw.
Ähnlich wie beim FlowLayout steht ein zusätzlicher Konstruktor zur Verfügung, der es erlaubt, die Größe der horizontalen und vertikalen Lücken zu verändern:
public void GridLayout(int rows, int columns, int hgap, int vgap) |
java.awt.GridLayout |
Die größere Kontrolle des Programms über das Layout besteht nun darin, daß der Umbruch in die nächste Zeile genau vorhergesagt werden kann. Anders als beim FlowLayout erfolgt dieser nicht erst dann, wenn keine weiteren Elemente in die Zeile passen, sondern wenn dort so viele Elemente plaziert wurden, wie das Programm vorgegeben hat.
Das folgende Beispiel zeigt ein Fenster mit einem Gitter der Größe 4*2 Elemente, das ingesamt sieben Buttons anzeigt:
|
![]() |
|
![]() |
Die Ausgabe des Programms ist:
Abbildung 21.3: Verwendung der Klasse GridLayout
Wenn wir die Größe des Fensters nicht durch einen Aufruf von pack, sondern manuell festgelegt hätten, wäre an dieser Stelle ein wichtiger Unterschied zwischen den beiden bisher vorgestellten Layoutmanagern deutlich geworden. Abbildung 21.4 zeigt das veränderte Listing 21.2, bei dem die Größe des Fensters durch Aufruf von setSize(500,200); auf 500*200 Pixel festgelegt und der Aufruf von pack entfernt wurde:
Abbildung 21.4: Das FlowLayout in einem größeren Fenster
Hier verhält sich das Programm noch so, wie wir es erwarten würden, denn die Buttons haben ihre Größe behalten, während das Fenster größer geworden ist. Anders sieht es dagegen aus, wenn wir die Fenstergröße in Listing 21.3 ebenfalls auf 500*200 Pixel fixieren:
Abbildung 21.5: Das GridLayout in einem größeren Fenster
Nun werden die Buttons plötzlich sehr viel größer als ursprünglich angezeigt, obwohl sie eigentlich weniger Platz in Anspruch nehmen würden. Der Unterschied besteht darin, daß ein FlowLayout die gewünschte Größe eines Dialogelements verwendet, um seine Ausmaße zu bestimmen. Das GridLayout dagegen ignoriert die gewünschte Größe und dimensioniert die Dialogelemente fest in der Größe eines Gitterelements. Ein LayoutManager hat also offensichtlich die Freiheit zu entscheiden, ob und in welcher Weise er die Größen von Fenster und Dialogelementen den aktuellen Erfordernissen anpaßt.
Wir werden am Ende dieses Abschnitts auch Möglichkeiten kennenlernen, durch Schachteln von Layoutmanagern beide Möglichkeiten zu kombinieren: Das feste Gitterraster bleibt erhalten, aber die einzelnen Komponenten innerhalb des Gitters werden in ihrer gewünschten Größe angezeigt. Am Ende von Kapitel 22 werden wir zusätzlich kurz auf die verschiedenen Größen von Dialogelementen zurückkommen, wenn wir zeigen, wie selbstdefinierte Komponenten erzeugt werden. |
![]() |
|
![]() |
Das BorderLayout verfolgt einen anderen Ansatz als die beiden vorigen Layoutmanager, denn die Positionierung der Komponenten wird nicht mehr primär durch die Reihenfolge der Aufrufe von add bestimmt. Statt dessen teilt das BorderLayout den Bildschirm in fünf Bereiche auf, und zwar in die vier Ränder und das Zentrum. Durch Angabe eines Himmelsrichtungs-Strings wird beim Aufruf von add angegeben, auf welchem dieser Bereiche die Komponente plaziert werden soll:
Zur Übergabe dieses Parameters gibt es die Methode add der Klasse Container in einer Variante mit einem String als ersten Parameter:
public void add(String name, Component comp) |
java.awt.Container |
Das folgende Beispiel zeigt die Anordnung von fünf Buttons in einem BorderLayout. Jeweils einer der Buttons wird auf die vier Randbereiche verteilt, und der fünfte Button steht in der Mitte. Die Größe des Fensters wird fest auf 300*200 Pixel eingestellt:
|
![]() |
|
![]() |
Die Ausgabe des Programms ist:
Abbildung 21.6: Verwendung der Klasse BorderLayout
Bezüglich der Skalierung der Komponenten verfolgt BorderLayout einen Mittelweg zwischen FlowLayout und GridLayout. Während FlowLayout die Komponenten immer in ihrer gewünschten Größe beläßt und GridLayout sie immer skaliert, ist dies bei BorderLayout von verschiedenen Faktoren abhängig:
Auch beim BorderLayout kann die Größe der Lücken zwischen den Elementen an den Konstruktor übergeben werden:
public BorderLayout(int hgap, int vgap) |
java.awt.Borderlayout |
Wenn das vorige Beispiel ein BorderLayout mit einer vertikalen und horizontalen Lücke von 10 Pixeln definieren würde, wäre die Ausgabe des Programms wie folgt:
Abbildung 21.7: Ein BorderLayout mit Lücken
Das GridBagLayout ist der aufwendigste Layoutmanager in Java. Er erlaubt eine sehr flexible Gestaltung der Oberfläche und bietet viele Möglichkeiten, die in den anderen Layoutmanagern nicht zu finden sind. Der Preis dafür ist eine etwas kompliziertere Bedienung und ein höherer Einarbeitungsaufwand. Wir wollen in diesem Abschnitt die Klasse GridBagLayout vorstellen und ihre grundlegenden Anwendungsmöglichkeiten besprechen.
Um mit einem GridBagLayout zu arbeiten, ist wie folgt vorzugehen:
Das könnte beispielsweise so aussehen
001 ... 002 GridBagLayout gbl = new GridBagLayout(); 003 GridBagConstraints gbc = new GridBagConstraints(); 004 setLayout(gbl); 005 List list = new List(); 006 gbc.gridx = 0; 007 gbc.gridy = 0; 008 gbc.gridwidth = 1; 009 gbc.gridheight = 1; 010 gbc.weightx = 100; 011 gbc.weighty = 100; 012 gbc.fill = GridBagConstraints.BOTH; 013 gbl.setConstraints(list, gbc); 014 add(list); 015 ... |
Das Geheimnis der korrekten Verwendung eines GridBagLayout liegt also in der richtigen Konfiguration der Membervariablen der GridBagConstraints-Objekte. Es stehen folgende zur Verfügung:
public int gridx public int gridy public int gridwidth public int gridheight public int anchor public int fill public double weightx public double weighty public Insets insets public int ipadx public int ipady |
java.awt.GridBagConstraints |
Ihre Bedeutung ist:
Um die Anwendung der Parameter zu veranschaulichen, wollen wir uns ein Beispiel ansehen. Das zu erstellende Programm soll ein Fenster mit sechs Dialogelementen entsprechend Abbildung 21.8 aufbauen. Die Liste auf der linken Seite soll beim Skalieren in beide Richtungen vergrößert werden. Die Textfelder sollen dagegen lediglich in der Breite wachsen, ihre ursprüngliche Höhe aber beibehalten. Bei vertikaler Vergrößerung des Fensters sollen sie untereinander stehen bleiben. Die Beschriftungen sollen ihre anfängliche Größe beibehalten und - unabhängig von der Fenstergröße - direkt vor den Textfeldern stehen bleiben. Auch der Button soll seine ursprüngliche Größe beibehalten, wenn das Fenster skaliert wird. Zudem soll er immer in der rechten unteren Ecke stehen. Zwischen den Dialogelementen soll ein Standardabstand von zwei Pixeln eingehalten werden.
Abbildung 21.8: Beispiel für GridBagLayout
Wir konstruieren das GridBagLayout als Zelle der Größe drei mal drei gemäß Abbildung 21.9:
Abbildung 21.9: Zellenschema für GridBagLayout-Beispiel
Die Listbox beginnt also in Zelle (0, 0) und erstreckt sich über eine Zelle in horizontaler und drei Zellen in vertikaler Richtung. Die beiden Labels liegen in Spalte 1 und den Zeilen 0 bzw. 1. Die Textfelder liegen eine Spalte rechts daneben. Textfelder und Beschriftungen sind genau eine Zelle breit und eine Zelle hoch. Der Button liegt in Zelle (2, 2). Die übrigen Eigenschaften werden entsprechend unserer Beschreibung so zugewiesen, daß die vorgegebenen Anforderungen erfüllt werden:
001 /* Listing2106.java */ 002 003 import java.awt.*; 004 import java.awt.event.*; 005 006 public class Listing2106 007 extends Frame 008 { 009 public static void main(String[] args) 010 { 011 Listing2106 wnd = new Listing2106(); 012 wnd.setVisible(true); 013 } 014 015 public Listing2106() 016 { 017 super("Test GridBagLayout"); 018 setBackground(Color.lightGray); 019 //WindowListener hinzufügen 020 addWindowListener( 021 new WindowAdapter() { 022 public void windowClosing(WindowEvent event) 023 { 024 setVisible(false); 025 dispose(); 026 System.exit(0); 027 } 028 } 029 ); 030 //Layout setzen und Komponenten hinzufügen 031 GridBagLayout gbl = new GridBagLayout(); 032 GridBagConstraints gbc; 033 setLayout(gbl); 034 035 //List hinzufügen 036 List list = new List(); 037 for (int i = 0; i < 20; ++i) { 038 list.add("This is item " + i); 039 } 040 gbc = makegbc(0, 0, 1, 3); 041 gbc.weightx = 100; 042 gbc.weighty = 100; 043 gbc.fill = GridBagConstraints.BOTH; 044 gbl.setConstraints(list, gbc); 045 add(list); 046 //Zwei Labels und zwei Textfelder 047 for (int i = 0; i < 2; ++i) { 048 //Label 049 gbc = makegbc(1, i, 1, 1); 050 gbc.fill = GridBagConstraints.NONE; 051 Label label = new Label("Label " + (i + 1)); 052 gbl.setConstraints(label, gbc); 053 add(label); 054 //Textfeld 055 gbc = makegbc(2, i, 1, 1); 056 gbc.weightx = 100; 057 gbc.fill = GridBagConstraints.HORIZONTAL; 058 TextField field = new TextField("TextField " + (i +1)); 059 gbl.setConstraints(field, gbc); 060 add(field); 061 } 062 //Ende-Button 063 Button button = new Button("Ende"); 064 gbc = makegbc(2, 2, 0, 0); 065 gbc.fill = GridBagConstraints.NONE; 066 gbc.anchor = GridBagConstraints.SOUTHEAST; 067 gbl.setConstraints(button, gbc); 068 add(button); 069 //Dialogelemente layouten 070 pack(); 071 } 072 073 private GridBagConstraints makegbc( 074 int x, int y, int width, int height) 075 { 076 GridBagConstraints gbc = new GridBagConstraints(); 077 gbc.gridx = x; 078 gbc.gridy = y; 079 gbc.gridwidth = width; 080 gbc.gridheight = height; 081 gbc.insets = new Insets(1, 1, 1, 1); 082 return gbc; 083 } 084 } |
Listing2106.java |
Das Programm besitzt eine kleine Hilfsmethode makegbc, mit der auf einfache Weise ein neues GridBagConstraints-Objekt für einen vorgegebenen Bereich von Zellen erzeugt werden kann. Die übrigen Membervariablen werden im Konstruktor der Fensterklasse zugewiesen. Abbildung 21.10 zeigt das Fenster nach dem Skalieren in x- und y-Richtung.
Abbildung 21.10: Das GridBagLayout-Beispiel nach dem Skalieren
Ein Null-Layout wird erzeugt, indem die Methode setLayout mit dem Argument null aufgerufen wird. In diesem Fall verwendet das Fenster keinen Layoutmanager, sondern überläßt die Positionierung der Komponenten der Anwendung. Für jedes einzufügende Dialogelement sind dann drei Schritte auszuführen:
Der erste und letzte Schritt unterscheiden sich nicht von unseren bisherigen Versuchen, bei denen wir vordefinierte Layoutmanager verwendet haben. Im zweiten Schritt ist allerdings etwas Handarbeit notwendig. Größe und Position des Dialogelements können mit den Methoden move und setSize oder - noch einfacher - mit setBounds festgelegt werden:
public void setBounds( int x, int y, int width, int height ) |
java.awt.Component |
Der Punkt (x,y) bestimmt die neue Anfangsposition des Dialogelements und (width, height) seine Größe.
Das folgende Listing demonstriert diese Vorgehensweise am Beispiel einer treppenartigen Anordnung von fünf Buttons:
|
![]() |
|
![]() |
Die Ausgabe des Programms ist:
Abbildung 21.11: Verwendung des Null-Layouts
Eines der Schlüsselkonzepte zur Realisierung komplexer, portabler Dialoge ist die Fähigkeit, Layoutmanager schachteln zu können. Dazu wird an der Stelle, die ein Sublayout erhalten soll, einfach ein Objekt der Klasse Panel eingefügt, das einen eigenen Layoutmanager erhält. Dieses Panel kann mit Dialogelementen bestückt werden, die entsprechend dem zugeordneten Unterlayout formatiert werden.
Wenn wir an die in Abbildung 17.1 vorgestellte Klassenhierarchie innerhalb des AWT denken, werden wir uns daran erinnern, daß ein Panel die einfachste konkrete Containerklasse ist. Sie erbt alle Eigenschaften von Container und bietet damit die Möglichkeit, Komponenten aufzunehmen und mit Hilfe eines Layoutmanagers auf dem Bildschirm anzuordnen.
Das folgende Beispiel zeigt einen Dialog, der ein GridLayout der Größe 1*2 Elemente verwendet. Innerhalb des ersten Elements wird ein Panel mit einem GridLayout der Größe 3*1 Elemente verwendet, innerhalb des zweiten Elements ein BorderLayout:
|
![]() |
|
![]() |
Die Ausgabe des Programms ist:
Abbildung 21.12: Verwendung eines geschachtelten Layouts
Geschachtelte Layouts können auch dann sinnvoll verwendet werden, wenn innerhalb der Bestandteile eines BorderLayouts mehrere Komponenten untergebracht werden sollen oder wenn die Komponenten eines skalierenden Layoutmanagers ihre ursprüngliche Größe beibehalten sollen. |
![]() |
|
![]() |
Das folgende Beispiel demonstriert beide Anwendungen anhand eines BorderLayouts, das im South-Element zwei rechtsbündig angeordnete Buttons in Originalgröße und im Center-Element sechs innerhalb eines GridLayouts der Größe 3*2 Elemente angeordnete, skalierte Buttons enthält:
|
![]() |
|
![]() |
Die Ausgabe des Programms ist:
Abbildung 21.13: Ein weiteres Beispiel für geschachtelte Layouts
|
Go To Java 2, Addison Wesley, Version 1.0.2, © 1999 Guido Krüger, http://www.gkrueger.com |