Tjo, es gibt in der Programmierung meiner Meinung nach nichts nervenaufreibenderes als die Entwicklung einer Bedienoberfläche.
- Ist alles gut positioniert?
- Ist die GUI intuitiv?
- Stimmt die Tabluatorreihenfolge?
- Welches Farbschema ist passend?
- Sind ausreichend Hilfestellungen vorhanden?
und so weiter und so weiter …
Alles wichtige Fragen, doch um sich mit den Feinheiten davon auseinandersetzen zu dürfen, muss man erstmal wissen wie man eine GUI überhaupt erzeugt! Und genau das möchte ich in den kommenden Blogposts behandeln und zwar mit Java unter Zuhilfenahme der Swing Bibliotheken.
Ein erster kurzer Überblick über die kommenden Themen
- Teil 1: Einführung – enthält ein erstes Hello Swing, sowie eine Erklärung der Aufgabenstellung
- Teil 2: Der GUI Prototyp – wir basteln einen Prototypen, der StandbyScreen (JLabel, BorderLayout)
- Teil 3: Der GUI Prototyp – wir basteln weiter am Prototypen, die Datenanzeige (BoxLayout, JTextField)
- Teil 4: Interaktion mit der GUI – der Prototyp erwacht zum Leben
- Teil 5: Hinter der GUI rattert es – Threadsicherheit ist das Thema dieser Lektion
Was ist Swing überhaupt?
Nun die Swing Bibliotheken umfassen allerlei grafische Komponenten wie z.B Buttons, Split Panes und Tables. Ich falle hier in die englische Sprache, da diese Begriffe später auch in der Entwicklung verwendet werden. Viele der in Swing enthaltenen Komponenten bieten zudem brauchbare Funktionalitäten wie ein Sortieren des Inhalts, Drucken, drag’n’drop. Swing selbst ist seit Java 1.2 Bestandteil der Runtime und baut auf das ältere AWT (Abstract Window Toolkit) auf. Es gehört zu den JFC (Java Foundation Classes) die eine Sammlung von APIs für die GUI Entwicklung einhält, und greift auf diese zusätzlichen APIs auch zu.
Hello Swing
Um einen ersten Vorgeschmack auf das zu geben, was da kommt, möchte ich mit einem Hello Swing Beispiel beginnen. Man bekommt dabei einen ersten Einblick in die Notwendigkeiten, die der Aufbau einer GUI mit Swing mit sich bringen. Eine kurze Erklärung dazu befindet sich an den jeweiligen Stellen im Sourcecode.
package at.nullpointer.learningswing.helloswing; import javax.swing.JFrame; import javax.swing.JLabel; /** * Hello Swing - Simple GUI-Demo * * @author Tom * */ public class HelloSwing { public static void main(String[] args) { // Zwecks Threadsicherheit wird die Methode die die // GUI anzeigt vom event-dispatching Thread gestartet javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } /** * Erzeut ein Fenster und zeigt es. */ private static void createAndShowGUI() { // Ein Fenster erzeugen JFrame frame = new JFrame("Hello Swing"); // Dem X Button des Fensters rechts oben wird die Funktion // des Beendens des Fensters zugewiesen frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Ein Label mit unserem Hallo erzeugen JLabel label = new JLabel("Hello Swing"); // Das Label auf die Darstellbare Oberfläche stecken frame.getContentPane().add(label); // Das Fenster komprimieren frame.pack(); // Das Fenster sichtbar machen frame.setVisible(true); } }
Herangezogen hab ich für diesen Quelltext, das Original der Java Einführung von Sun/Oracle, die man hier findet.
Unsere Zielanwendung
Jede einzelne Swing Komponente anzuführen und zu erklären würde den Rahmen dieses Eintrags sprengen. Dennoch haben wir viel vor. Ich möchte jetzt ein Szenario vorstellen, für das wir eine GUI entwickeln wollen.
Eine Reinigungsfirma mit 4 Filialen überlegt den Einsatz von Stammkundenkarten, um die Kundschaft länger zu binden, Kundenprofile anlegen zu können für gezielte Werbemaßnahmen und das Reinigungsbedürfnis der Kundschaft analysieren zu können. Zur Umsetzung benötigen sie nun eine Anwendung die von einem Kartenlesegerät die Kundennummer einliest, diese mit dem zentralen Server der Firmensoftware abgleicht und um dann der Verkäuferin in der Filiale diverse Information anzeigt, wie z.B. Name und Adresse, sowie Telefonnummer. Es soll außerdem angezeigt werden ob die Karte aktiviert wurde. Auch die letzte Aktivität der Karte soll der Verkäuferin angezeigt werden (inkl. Filialnummer). Als zusätzliches Feature soll man neue Karten registrieren können, man muss dazu Name Adresse und Telefonnummer einer noch nicht aktivierten Karte zuweisen können.
Da wir hier nur ein Fallbeispiel aufbereiten, wollen wir nicht gegen einen wirklichen Kartenleser und eine richtige Firmensoftware programmieren. Wir verwenden sogenannte Mock-Objekte, oder auch Dummy-Objekte, die sehr vereinfacht entsprechende Funktionalität zur verfügung stellen.
Der MockCardReader:
package at.nullpointer.learningswing.mock; /** * Mockobjekt als Simulation eines Kundenkartenlesesystem * * @author fake * */ public class MockCardReader { private final int aktiveKdnr = 12345; private final int gesperrteKdnr = 54321; private final int neueKdnr = 66666; /** * Liefert eine aktive Kundennummer zurück Public Methode um JUnitTestfälle * zu unterstützen * * @return int */ public int getAktiveKdnr() { return aktiveKdnr; } /** * Liefert eine gesperrte Kundennummer zurück Public Methode um * JUnitTestfälle zu unterstützen * * @return int */ public int getGesperrteKdnr() { return gesperrteKdnr; } /** * Liefert eine neue Kundennummer zurück Public Methode um JUnitTestfälle zu * unterstützen * * @return int */ public int getNeueKdnr() { return neueKdnr; } /** * Liefert eine Kundennummer zurück * * @return */ public int getKdnr() { int choose = (int) (System.currentTimeMillis() % 3); switch (choose) { case 0: return aktiveKdnr; case 1: return gesperrteKdnr; case 2: return neueKdnr; default: return aktiveKdnr; } } }
Die MockFirmenSoftware:
package at.nullpointer.learningswing.mock; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * Simulation der Firmenkundendatenbank * * @author fake * */ public class MockCompanySoftware { private Map kundendaten = new HashMap(); /** * Erzeugt und befüllt initial die Datenbank */ public MockCompanySoftware() { Kundendaten kd1 = new Kundendaten(12345, "Max", "Mustermann", "Mustermannstraße 3#1111 MusterWien", 1305840610, true, new Date(2010, 10, 10), "Filiale 03"); Kundendaten kd2 = new Kundendaten(54321, "Maxime", "Musterfrau", "Wo anders 4#1111 MusterWien", 1231543656, false, new Date( 2010, 9, 10), "Filiale 03"); kundendaten.put(Integer.valueOf(kd1.getKdnr()), kd1); kundendaten.put(Integer.valueOf(kd2.getKdnr()), kd2); } /** * Man kann die Kundendaten eines Kunden über die Kundennummer abfragen * * @param kundennummer * @return Kundendaten wenn vorhanden, null wenn nicht vorhanden */ public Kundendaten getKundendaten(int kundennummer) { return kundendaten.get(Integer.valueOf(kundennummer)); } public String setKundendaten(Kundendaten kdata){ return "Daten gesandt"; } }
Das Kundendatenobjekt:
package at.nullpointer.learningswing.mock; import java.util.Date; /** * Objekt repräsentiert einen Kunden in der Datenbank * * @author fake * */ public class Kundendaten { private int kdnr; private String vorname; private String nachname; private String adresse; private long telefonnummer; private boolean aktiv; private Date lastAktive; private String filialname; public Kundendaten(int kdnr, String vorname, String nachname, String adresse, long telefonnummer, boolean aktiv, Date lastAktive, String filialname) { super(); this.kdnr = kdnr; this.vorname = vorname; this.nachname = nachname; this.adresse = adresse; this.telefonnummer = telefonnummer; this.aktiv = aktiv; this.lastAktive = lastAktive; this.filialname = filialname; } public int getKdnr() { return kdnr; } public void setKdnr(int kdnr) { this.kdnr = kdnr; } public String getVorname() { return vorname; } public void setVorname(String vorname) { this.vorname = vorname; } public String getNachname() { return nachname; } public void setNachname(String nachname) { this.nachname = nachname; } public String getAdresse() { return adresse; } public void setAdresse(String adresse) { this.adresse = adresse; } public long getTelefonnummer() { return telefonnummer; } public void setTelefonnummer(long telefonnummer) { this.telefonnummer = telefonnummer; } public boolean isAktiv() { return aktiv; } public void setAktiv(boolean aktiv) { this.aktiv = aktiv; } public Date getLastAktive() { return lastAktive; } public void setLastAktive(Date lastAktive) { this.lastAktive = lastAktive; } public String getFilialname() { return filialname; } public void setFilialname(String filialname) { this.filialname = filialname; } }
Um noch einen ungefähren Überblick darüber zu erhalten wie unsere GUI einmal aussehen wird, hier noch 3 Mockups, Beispielbilder, nach denen wir unsere GUI entwerfen werden.
Der StandbyScreen:
Anzeige der Kundendaten:
Eingabemaske für einen Neukunden:
Da wir nun ein ungefähres Bild davon haben, wie unsere Anwendungen auszusehen haben, und was sie können sollen gilt es selbiges umzusetzen. Damit werden wir uns im nächsten Teil dieser Serie beschäftigen. Vorerst erschaffen wir jedoch einen Prototypen der noch keinerlei Funktionsumfang beinhaltet.
Bis zum nächsten Teil dieser Reihe!
Schreibe einen Kommentar