Trace: • Die Layout Manager
An eine GUI Entwicklung ohne Layout Manager ist kaum zu denken. Doch um ansprechende GUIs zu entwickeln werden oftmals mehrere Layout Manager benötigt. Diese werden geschachtelt um die gewünschten Ergebnisse zu erhalten. Um die Schachtelung zu ermöglichen ist pro Layout Manager auch ein Panel nötig. Ehe man sich versieht entsteht eine Unmenge an Code und zwar nur um das GUI zu definieren.
Selbst der Einsatz von visuellen Designern erleichtert nur die Positionierung der Komponenten, nicht aber die Anzahl der Komponenten. Und je mehr Verschachtelungen ein GUI hat, desto träger und komplexer wird es.
Um den GUI Code minimal und vor allem übersichtlich zu halten, bietet JVx genau 3 Layout Manager mit denen dieses Ziel erreicht werden kann:
- BorderLayout
- FlowLayout
- FormLayout
Das BorderLayout bietet im Unterschied zum java.awt.BorderLayout die Möglichkeit die Margins zu beeinflussen. Ansonsten bietet es die gewohnten Bereiche: NORTH, WEST, EAST, SOUTH, CENTER.
Das FlowLayout ermöglicht die Vertikale und Horizontale Anordnung der Komponenten, die Verwendung von Margins und es bietet Stretching sowie Einflußnahme auf die Ausrichtung der Komponenten innerhalb des Layouts. Im Prinzip ergänzt es das java.awt.FlowLayout um die fehlenden Möglichkeiten.
FormLayout
Wie der Name schon vermuten lässt, dient dieser Layout Manager für die Erstellung von Formularen. Das ist aber nur ein Bruchteil der Aufgaben die sich damit noch lösen lassen. Die Idee hinter diesem Layout Manager war: Erstellen von komplexen Formularen durch den Verzicht auf Schachtelung und Komplexität.
Das Form Layout arbeitet Anker basierend. Ein Anker definiert eine Position im GUI und kann absolut oder relativ, zu einem anderen Anker, positioniert werden.
Damit ist es zum Beispiel möglich ein Panel in tabellarischer Form zu unterteilen, wie auch das java.awt.GridLayout. Darüber hinaus kann es aber auch als java.awtGridBagLayout angesehen werden, jedoch ohne den damit verbundenen Komplexitätsgrad.
Anhand einiger Beispiele wollen wir die Verwendung zeigen:
Einfaches Anwendungsbeispiel
Ein Formular mit 2 Spalten (Standardeinstellung):
Die Anker sind wie folgt definiert:
Der dazugehörige Source Code:
UIFormLayout layout = new UIFormLayout(); UIPanel panDetail = new UIPanel(layout); panDetail.add(new UILabel("Filename:")); panDetail.add(new UIEditor(rdbFiles, "FILENAME")); panDetail.add(new UILabel("Type:")); panDetail.add(new UIEditor(rdbFiles, "TYPE")); panDetail.add(new UILabel("Size:")); panDetail.add(new UIEditor(rdbFiles, "FILESIZE")); panDetail.add(new UILabel("Created:")); panDetail.add(new UIEditor(rdbFiles, "CREATED")); panDetail.add(new UILabel("Created by:")); panDetail.add(new UIEditor(rdbFiles, "CREATED_BY")); panDetail.add(new UILabel("Changed:")); panDetail.add(new UIEditor(rdbFiles, "CHANGED")); panDetail.add(new UILabel("Changed by:")); panDetail.add(new UIEditor(rdbFiles, "CHANGED_BY"));
Um 4 Spalten zu erhalten ist der Aufruf:
layout.setNewlineCount(4);
vollkommen ausreichend:
Komplexes Anwendungsbeispiel
Ein etwas komplexeres GUI zeigt folgende Darstellung:
Und der passende Source Code:
UIFormLayout flDetails = new UIFormLayout(); UIGroupPanel gpanDedails = new UIGroupPanel(); gpanDedails.setLayout(flDetails); gpanDedails.add(icoImage, flDetails.getConstraints(0, 0, 1, 7)); gpanDedails.add(butLoadImage, flDetails.getConstraints(0, 8)); gpanDedails.add(edtFilename, flDetails.getConstraints(1, 8)); flDetails.setHorizontalGap(15); gpanDedails.add(lblSalutation, flDetails.getConstraints(2, 0)); flDetails.setHorizontalGap(5); gpanDedails.add(edtSalutation, flDetails.getConstraints(3, 0)); gpanDedails.add(lblAcademicTitle, flDetails.getConstraints(2, 1)); gpanDedails.add(edtAcademicTitle, flDetails.getConstraints(3, 1)); gpanDedails.add(lblFirstName, flDetails.getConstraints(2, 2)); gpanDedails.add(edtFirstName, flDetails.getConstraints(3, 2, -1, 2)); gpanDedails.add(lblLastName, flDetails.getConstraints(2, 3)); gpanDedails.add(edtLastName, flDetails.getConstraints(3, 3, -1, 3)); gpanDedails.add(lblSocialSecurityNr, flDetails.getConstraints(2, 4)); gpanDedails.add(edtSocialSecurityNr, flDetails.getConstraints(3, 4)); gpanDedails.add(lblBirthday, flDetails.getConstraints(4, 4)); gpanDedails.add(edtBirthday, flDetails.getConstraints(5, 4, -1, 4)); gpanDedails.add(lblHealthInsurance, flDetails.getConstraints(2, 5)); gpanDedails.add(edtHealthInsurance, flDetails.getConstraints(3, 5, -1, 5)); gpanDedails.add(lblStreet, flDetails.getConstraints(2, 6)); gpanDedails.add(edtStreet, flDetails.getConstraints(3, 6, -3, 6)); gpanDedails.add(lblNr, flDetails.getConstraints(-2, 6)); gpanDedails.add(editNr, flDetails.getConstraints(-1, 6)); gpanDedails.add(lblZip, flDetails.getConstraints(2, 7)); gpanDedails.add(edtZip, flDetails.getConstraints(3, 7)); gpanDedails.add(lblTown, flDetails.getConstraints(4, 7)); gpanDedails.add(edtTown, flDetails.getConstraints(5, 7, -1, 7));
Fehler Dialog
Als letztes Beispiel zeigen wir den Error Dialog aus dem Framework, diesmal mit direkter Anker Verwendung:
Und der Source Code:
foMain = new UIFormLayout(); foMain.setVerticalAlignment(IAlignmentConstants.ALIGN_TOP); foMain.setMargins(new UIInsets(7, 7, 7, 7)); setLayout(foMain); add(icon); add(taMessage, foMain.getConstraints(foMain.getTopMarginAnchor(), foMain.createAnchor(foMain.getConstraints(icon). getRightAnchor(), 5), null, foMain.getRightMarginAnchor())); add(butOK, foMain.getConstraints(null, null, foMain.getBottomMarginAnchor(), foMain.getRightMarginAnchor())); add(butDetails, foMain.getConstraints(null, null, foMain.getBottomMarginAnchor(), foMain.createAnchor(foMain.getConstraints(butOK). getLeftAnchor(), -5)));
Hinweis
Es gibt eine Demo Applikation um die Anker des FormLayout zu untersuchen. Der Source Code ist bei hosted on github hinterlegt.