HOWTO: GUI mit Swing – Teil 3: Prototyp – Die Datenview

Wie entwickelt man eigentlich eine GUI mit Java Swing? Eine mehrteilige Einführung in dieses Thema. Teil 3 erweitert den Prototypen um Eingabefelder u.a.


Willkommen zurück bei der Reihe GUI programmieren mit Java Swing. In den vorigen Teilen haben wir uns ein HelloSwing-Beispiel angesehen, und mit diesem anhand einer konkreten Problemstellung einen ersten Prototypen entworfen. In diesem Teil werden wir diesen Prototypen nun um eine weitere Sicht, der View-Sicht erweitern und uns etwas mehr mit verschiedenen Schichten des JFrames sowie den Layouts der Komponenten auseinandersetzen. Um auch noch die Edit-Schicht umzusetzen wird dann noch in einem Beispiel das JTextField sowei der JButton vorgestellt, ehe man sich zum Gestigen des hier erworbenen Wissens selbst ans Umsetzen der Edit-View setzen kann. Diese wird in den nächsten Teilen zur Umsetzung der Funktionalität erforderlich sein.

Zur Erinnerung an die bereits besprochenen und noch geplanten Themen hier noch eine Auflistung selbiger:

      Aufgabe aus Teil 2

      Aufgabe in Teil 2 war es den Prototypen um einen Zusätzlichen JLabel zu erweitern sowie die Schriftgröße unseres StandByJLabels zu vergrößern. Hier kurz der Lösungsweg skizziert:

      Zusätzliches Label:

      Um ein zusätzliches Label zu erzeugen kopieren wir unsere StandbyJLabel Klasse und benennen sie beispielsweise FooterLabel. Damit sie am richtigen Fleck angezeigt wird, und das egal in welchem State der Prototyp aufgerufen wird fügen wir das neue JLabel in der createGUI Methode dem JFrame hinzu:

      	public static JFrame createGUI() {
      		// ... restlicher Code ...
      
      		frame.add(new FooterJLabel(), BorderLayout.PAGE_END);
      
      		return frame;
      	}

      Das JLabel wurde nun dem PAGE_END Bereichs des BorderLayouts zugewiesen und erscheint nun unten im JFrame wenn wir die Anwendung starten. Wir müssen noch die Caption des FooterLabels auf uns selbst oder unsere Domain z.B. „by nullpointer.at“ ändern. Damit der Text rechts unten im JFrame erscheint, verändern wir die Horizontale Ausrichtung von CENTER auf RIGHT

      		this.setHorizontalAlignment(RIGHT);
      Schriftgröße:

      Im Konstruktor der Klasse StandByJLabel wurden folgende Zeilen hinzugefügt:

      		Font font = new Font("Dialog", Font.PLAIN, 24);
      		this.setFont(font);

      Diese erzeugen zuerst ein Fontobjekt, bei dem die Schriftgröße neu gesetzt wird, und dannach wiesen wir sie dem Label zu.

      Habt ihr alles richtig gemacht sollte der StandbyScreen in etwa so aussehen wie in der folgenden Abbildung.

      Fertiger StandbyScreen inkl. Hausübung Unfertige View Sicht

      Startet ihr die Anwendung mit dem Parameter 2 um die Datenansicht zu starten seht ihr dass der Footer hier ebenfalls angezeigt wird, der Rest der Anwendung jedoch noch grau ist und somit nicht befüllt. Dem wenden wir uns jetzt zu.

      Die View-Sicht

      Ein Entwurf einer Kundendatenanzeige für eine Java Swing OberflächeDie View Sicht strotzt nur so von GUI-Elementen. Zum einen haben wir eine Statusanzeige, die immer oben im Bild zu sehen sein wird. Hierfür werden wir erneut auf das BorderLayout zurückgreifen,welches wir mit einem JLabel füttern.

      Danns sind da noch eine Menge Daten über den Kunden die es anzuzeigen gibt.

      An der Aufteilung im Mockup können wir erkennen, dass das BorderLayout hierbei vermutlich an seine Grenzen stößt, weshalb wir das BoxLayout in diesem Artikel behandeln. Ansonsten benötigen wir zur Darstellung der Daten JLabel über JLabel, noch nicht viel Neues in Sicht.

      Damit die Sache mit den neuen Layouts unseren Footer nicht zerstört werden wir dabei erstmals eine weitere Schicht einführen, die unsere Darstellungstypen von einander trennen.

      Abschließend wird dann noch das JTextField vorgestellt, mit dem man man den User zu Eingaben auffordern kann. In einem kleinen Fallbeispiel werden wir ebenfalls den JButton kurz erläutern und als Aufgabe dieses Teils gilt es die Edit-Sicht selbst nachzubauen, was mit hier erworbenen Wissen nicht allzu schwer fallen sollte.

      Zwei JLabel ein BorderLayout.CENTER

      Wenn wir die View nun umsetzen wollen sehen wir dass wir mehr als nur ein Label benötigen werden. Ganze 12 Stück für die jeweiligen Feldbeschriftungen und die Darstellung des Inhalts sind notwendig. Wie in der vorigen Lektion beschrieben beinhaltet das Borderlayout eine Fläche in der Mitte zur Darstellung des Content und eine jeweils seitlich. Was passiert wenn wir da mehr als ein Label reinstecken? Mehr als ein Label in einen Bereich von BorderLayoutTestweise erstellen wir mal ein JFrame und packen 3 Labels rein. Das sollte mittlerweile kein Problem darstellen, weshalb ich hier auf den Source verzichte. Es wurde Label 1 in Gelb dem linken Bereich, dem LINE_START zugewiesen, Label 2 in Rot und Label 3 in Grün dem Bereich in der Mitte, BorderLayout.Center. Und tada Label 3 hat Label 2 überschrieben. Wir müssen also andere Wege gehen wenn wir die 12 Labels anzeigen wollen. Zum Beispiel mit einem anderen Layout:

      Das BoxLayout

      Um dem oben genannten Problem Herr zu werden bietet sich bei der Struktur unsere Ausgaben das Boxlayout an. Dieses offeriert zwei Möglichkeiten die Elemente, die es beherbergt zu verwalten. Entweder es teilt den verfügbaren Bereich horizontal oder vertikal auf alle Elemente auf.

      BoxLayout Typen

      Dabei wird der verfügbare Bereich nicht einfach nur auf alle Elemente verteilt, sondern es werden diese nach Reihenfolge des Hinzufügens von Links nach Rechts bzw. von Oben nach Unten angeordnet und verbrauchen dabei genau soviel Platz wie es das Element notwendig macht.

      Zugewiesen wird das BoxLayout auf folgende Weise:

      pane.setLayout(new BoxLayout(pane,BoxLayout.PAGE_AXIS));

      BoxLayoutDemo resizedBoxLayoutDemo Das Ergebnis ist hierbei auch mit einer kleinen Beispielanwendung verdeutlicht. Verändern wir die Fenstergröße,nutzten die Elemente weiterhin nur den von ihnen ursprünglich belegten Platz. Um nun auch im BoxLayout designtechnische Möglichkeiten zu haben gibt es folgende 3 Möglichkeiten:

      rigid area

      Diese verwendet man wenn man zwischen zwei Elementen einen fixen Abstand einbauen möchte.

              pane.add(label1);
              pane.add(Box.createRigidArea(new Dimension(5,5)));
              pane.add(label2);

      Dieser Code erzeugt zwischen Label 1 und Label 2 einen 5 Pixel breiten oder 5 Pixel hohen Leerbereich, je nach Ausrichtung des BoxLayouts.

      rigid area zwischen den JLabel

      glue

      Mithilfe des Glues nutzt man den Platz der zur Verfügung steht komplett aus. Alles was vor dem Glue hinzugefügt wurde “klebt” an der einen Seite, alles was dannach hinzugefügt wurde “klebt” an der anderen. Werden mehrere Glues hinzugefügt wird der verfügbare Platz zwischen diesen zu gleichen Teilen aufgeteilt.

              pane.add(label1);
              pane.add(Box.createGlue());
              pane.add(label2);
              pane.add(Box.createGlue());
              pane.add(label3);

      image

      custom Box.Filler

      Der Custom Box Filler ermöglicht es einem eine Componente einzufügen die einen minimalen, einen bevorzugten und einen maximal definierten Platz ausfüllt.

              pane.add(label1);
              Dimension minSize = new Dimension(5, 20);
              Dimension prefSize = new Dimension(50, 25);
              Dimension maxSize = new Dimension(100, 100);
              pane.add(new Box.Filler(minSize, prefSize, maxSize));
              pane.add(label2);
              pane.add(new Box.Filler(minSize, prefSize, maxSize));
              pane.add(label3);
      Minimaler Abstand Box.Filler minimal
      Bevorzugter Abstand Box.Filler preferred
      Maximaler Abstand Box.Filler maximal

      Die fertige View

      Damit wir nun unsere View mit dem neuen Wissen anpassen können müssen wir erstmal in der Prototype Klasse in unserem Switch einen Funktionsaufruf im Falle einer 2 als Parameter einfügen. Dieser wird folgende Funktion aufrufen:

      	public JFrame fillFrameWithDataContent(JFrame frame) {
      		// wir erzeugen uns die Datenansicht
      		JPanel showData = new ShowDataJPanel();
      		// und fügen sie dem BorderLayout in der Mitt hinzu
      		frame.getContentPane().add(showData, BorderLayout.CENTER);
      		// Zur optischen Verschönerung erzeugen wir in den noch nicht
      		// belegten Feldern des Borderlayouts noch Rot grundierte Bereiche
      		JPanel placeholder_top = new JPanel();
      		placeholder_top.setBackground(Color.RED);
      		JPanel placeholder_right = new JPanel();
      		placeholder_right.setBackground(Color.RED);
      		JPanel placeholder_left = new JPanel();
      		placeholder_left.setBackground(Color.RED);
      		frame.getContentPane().add(placeholder_top, BorderLayout.PAGE_START);
      		frame.getContentPane().add(placeholder_right, BorderLayout.LINE_START);
      		frame.getContentPane().add(placeholder_left, BorderLayout.LINE_END);
      
      		return frame;
      	}

      In dieser Methode erzeugen wir ein JPanel. Dies ist wie die ContentPane ein Behälter, der weitere Elemente beinhalten kann und diese auch entsprechend den Layout-Vorgaben ausgibt. Hier kommt das Schichtenmodell von Swing wieder zu tragen. Damit mehrere verschiedene Layouts miteinander wirken können, tragen wir einzelne JPanels auf wie eine Grundierung bei auf einer Leinwand.

      Um die Definition des JPanels im JPanel zu halten haben wir das JPanel erweitert:

      package at.nullpointer.guiprototype.showdata;
      
      import java.awt.Color;
      import java.awt.Dimension;
      
      import javax.swing.Box;
      import javax.swing.BoxLayout;
      import javax.swing.JLabel;
      import javax.swing.JPanel;
      
      public class ShowDataJPanel extends JPanel {
      
      	public ShowDataJPanel(){
      
      		this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
      		this.setBackground(Color.RED);
      		this.setOpaque(true);
      
      		// Status Zeile
      		// Ein Container für die Zeile
      		JPanel statePanel = new JPanel();
      		// Mit dem BoxLayout.LINE_AXIS um die Elemente in der Zeile auszurichten
      		statePanel.setLayout(new BoxLayout(statePanel, BoxLayout.LINE_AXIS));
      		// Das erklärende Label
      		JLabel stateLabel = new ShowDataJLabel("Status");
      		// Das daten-haltende Label
      		JLabel stateContent = new ShowDataJLabel("aktiv");
      		// Wir wollen dass die Labels an der rechten Seite kleben
      		statePanel.add(Box.createHorizontalGlue());
      		statePanel.add(stateLabel);
      		// 5 Pixel Abstand zwischen den Label
      		statePanel.add(Box.createRigidArea(new Dimension(5, 0)));
      		statePanel.add(stateContent);
      		this.add(statePanel);
      
      		// .....
      
      	}
      
      }

      Hier wird das Layout wie weiter oben besprochen definiert und die Anordnung der Elemente vertikal gesetzt, so dass wir für jede Zeile die wir ausgeben wollen ein weiteres Objekt anfügen können. Der Anwendungsübliche rote Hintergrund wird natürlich nicht vergessen. Im Code zu sehen ist auch noch die erste Zeile. Hierfür erzeugen wir uns zuerst eine weitere Schicht in unserer Zwiebel, in der wir nur das Aussehen einer einzelnen Zeile definieren. Wir setzen das BoxLayout auf eine horizontale Aufteilung des Platzes und nutzen dann die Gestaltungsmöglichkeiten des BoxLayouts um den Inhalt des JPanel entsprechend den Vorgaben des Mocks zu verwirklichen. Unser überschriebenes JLabel bietet uns einige Gestaltungsmöglichkeiten und so kommen wir nach dem Einfügen der weiteren Felder ob individueller Abstände durch die rigid Area sowie nach unten geklebten Informationen über die Aktivität durch den VerticalGlue zu folgendem Ergebnis. Probiert doch selbst ob ihr das ebenfalls hinbekommt, damit ihr auch direkt ein Gefühl für die Auswirkungen des BoxLayouts bekommt.

      fertige View

      Das JTextField & der JButton

      JTextField und JButton DemoDas JTextField offeriert dem Programmierer die Möglichkeit den Benutzer zu Eingaben aufzufordern. Mit dem JButton wiederum kann man diese bestätigen, damit das Programm die neuen Daten verarbeiten kann. Beide Elemente sind notwendig um unser letztes Mockup umsetzten zu können. Da der prinzipielle Aufbau der View Seite sehr ähnelt gibt es hier nur eine kurze Einführung in die beiden neuen GUI Elemente. Das Umsetzen ist dann als Hausaufgabe zu sehen. Die Lösung dazu ist natürlich wieder im nächsten Teil angeführt.

      Das JTextField bietet alle Funktionalität an um Textelemente aufzunehmen. Hierbei gibt es verschiedene Abwandlungen wie z.B. das JPasswordField oder das JFormattedTextField. Ersteres versteckt nach außen welche Buchstaben man eingegeben hat, zweiteres dient zur Überprüfung von Eingaben bzw. Festlegung von Eingabekonventionen. Für unser Beispiel reicht jedoch bereits das normale JTextField, welches im folgenden Source kurz erklärt wird.

      		Dimension d = new Dimension(100,20);
      		JTextField txt_one = new JTextField();
      		txt_one.setMinimumSize(d);
      		JTextField txt_two = new JTextField("InitialText");
      		txt_two.setMinimumSize(d);

      Das erste Textfeld wird erzeugt und danach wird ihm eine Mindestgröße zugewiesen. Beim zweiten Textfeld haben wir zusätzlich noch eine initiale Befüllung im Konstruktor.

      Auch der JButton ist relativ simpel erstellt und hält einen Konstruktor mit einer Möglichkeit zur initialen Befüllung mit Text bereit

      JButton btn = new JButton("press");

      Auch er bietet wieder eine Methode an mit der minimale und maximale Größe gesetzt werden kann, womit unser derzeitiger Anspruch für einen GUI Prototypen abgedeckt ist.

      Man sieht, rein das Anzeigen dieser Komponenten ist keine Hexerei, die Magie dahinter ist wird dann im nächsten Teil dieser Reihe aufgedeckt.

      Aufgabenstellung

      Ein Entwurf einer Maske zur Kundenerfassung für eine Java Swing OberflächeEs gilt nun die Edit-Sicht mithilfe des in dieser Lektion erlangten Wissens umzusetzen, man soll ein EditJPanel erzeugen und auf dieser die notwendigen UIElemente platzieren. Wenn man den Prototypen mit dem Startparameter 3 startet, soll dieses sichtbar sein. Natürlich soll unser Footer nicht überschrieben werden. Die Ausgangssourcen sind hier zu finden: nullpointer.at HOWTO Swing – Teil3 Sourcen

      Have Fun!

      Ähnliche Artikel:

      Autor: Thomas Pummer

      Thomas Pummer ist Softwareentwickler an der Universität Wien. In seiner Freizeit betreut er das Open Source Projekt TrayRSS und werkt an diversen anderen kleinen Projekten. Er ist sehr interessiert an Open Source und Webentwicklung und testet gern neue Programmiersprachen.

      Ein Gedanke zu „HOWTO: GUI mit Swing – Teil 3: Prototyp – Die Datenview“

      Schreibe einen Kommentar

      Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

      *