1
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 500 – 00 – TH – 01
-----------------------------------------------------------------------------------
Programmieren in Java
Kapitel 5
5. Graphische Benutzeroberflächen 5.1 Grundprinzip
5.2 Java Foundation Classes – Überblick
5.3 Basisklassen der JFC-Hierarchie
5.4 Erstellung einer GUI-Anwendung
5.5 Beeinflussung des Erscheinungsbildes
5.6 Ausgewählte Swing-Komponenten-Klassen
5.7 Ereignisverarbeitung
5.8 Entwurfsmuster mit GUI-Bezug
Stand 05.10.2013
2
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 511 – 00 – TH – 02
-----------------------------------------------------------------------------------
Grundprinzip graphischer Benutzeroberflächen
Aufbau graphischer Benutzeroberflächen
◇ Eine graphische Benutzeroberfläche (Graphical User Interface, GUI) ist typischerweise aus hierarchisch strukturier-
ten Komponenten aufgebaut.
◇ Die einzelnen GUI-Komponenten – auch controls oder widgets ( = window gadgets) genannt – erfüllen jeweils spezielle
Aufgaben. Die meisten von ihnen ermöglichen es dem Benutzer, durch Eingaben mittels Maus, Tastatur oder einem
anderen Eingabegerät mit Ihnen und damit mit dem Programm zu interagieren.
◇ Die hierarchische Struktur einer graphischen Benutzeroberfläche ergibt sich dadurch, dass einige GUI-Komponenten,
Container genannt, andere Komponenten enthalten können.
An der "Spitze" jeder graphischen Benutzeroberfläche steht ein sogenannter Top-Level-Container. Die in ihm enthal-
tenen Komponenten können "elementare" Komponenten oder wiederum Container sein, welche dann weitere Kom-
ponenten enthalten können, usw.
Eine an einen Container gerichtete Aufgabe (z.B. paint(), "zeichne Dich") führt dieser für sich – soweit zutreffend – aus
und delegiert dann die weitere Ausführung an alle in ihm enthaltenen Komponenten.
Eine derartige Struktur führt programmtechnisch zu einer Implementierung des Entwurfsmusters Composite.
◇ Beispiele für elementare GUI-Komponenten :
▪ Beschriftung (Label)
▪ Textfeld (Text Field)
▪ Schaltfläche (Button)
▪ Auswahlfeld (Check Box)
▪ Auswahlliste (List, Combo Box)
▪ Menue (Menu)
◇ Beispiele für GUI-Container
▪ Fenster mit Rahmen (Frame)
▪ Dialogbox (Dialog Box)
▪ Menueleiste (Menu Bar)
▪ Werkzeugleiste (Tool Bar)
▪ Gruppierungsfeld (Panel)
◇ Beispiel : Rahmenfenster (Frame) mit Schaltfläche (Button) und Beschriftung (Label)
Interaktion mit dem Benutzer
◇ Die Interaktion mit dem Benutzer erfolgt ereignisgesteuert.
Jede auf eine GUI-Komponente fallende Benutzereingabe (Mausklick, Mausbewegung, Tastatureingabe, Auswahl aus
einem Menu usw) wird als Ereignis bezeichnet.
◇ Für jede Komponente kann festgelegt werden, auf welches Ereignis wie reagiert werden soll.
◇ Beim Eintritt eines Ereignisses wird die für die betreffende Komponente registrierte Reaktion ausgeführt.
3
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 521 – 00 – TH – 03
-----------------------------------------------------------------------------------
Java Foundation Classes – Überblick (1)
Bestandteile der Java Foundation Classes (JFC)
◇ Mit den JFC stellt Java eine breites Spektrum von Bibliotheks-Klassen zur Realisierung graphischer Funktionalität
und zum Aufbau von GUIs zur Verfügung.
◇ Die für die Anwendung in GUIs wichtigsten Klassen lassen sich im wesentlichen in die folgenden Gruppen einteilen :
▻ Klassen für elementare GUI-Komponenten
▻ Klassen für GUI-Container
▻ Klassen zur Gestaltung der GUI-Komponenten (Layout-Manager, Farben und Fonts)
▻ Klassen und Interfaces zur Ereignisverarbeitung (Listener, Adapter und Events)
◇ Die JFC umfassen im wesentlichen zwei – sich teilweise ersetzende und teilweise ergänzende – Frameworks :
▻ Abstract Windows Toolkit (AWT) Package java.awt mit mehreren Unterpaketen
▻ Die Swing-Klassen Package javax.swing mit mehreren Unterpaketen
◇ Zusätzlich gehören zu den JFC :
▻ Java 2D API (Klassen zur Realisierung fortgeschrittener 2D-Graphik, Bild- und Textbearbeitung sowie Drucken)
▻ Accessibility API (Klassen zur Realisierung von Interfaces für Behinderte)
▻ Klassen zur Unterstützung international einsetzbarer GUI-Applikationen, die sich leicht an die jeweilige Landes-
sprache und nationalen Konventionen anpassen. Hierzu gehört u.a. das Input Method Framework API.
Abstract Windows Toolkit (AWT)
◇ Ursprüngliches GUI-Paket in Java. Seit dem JDK 1.0 enthalten
Im JDK 1.1. wesentlich überarbeitet, insbesondere bezüglich der Ereignis-Bearbeitung
◇ Bildet auch die Grundlage für das spätere Swing-Paket.
◇ Die Implementierung der AWT-Klassen für die GUI-Komponenten verwendet die durch die Graphik-und Window-
Funktionalität des jeweiligen Betriebssystems zur Verfügung gestellten Komponenten ("heavyweight" components).
Das bedeutet,
- dass nur solche Funktionalitäten implementiert werden konnten, die auf allen wichtigen Plattformen, die Java
unterstützten, existierten ("kleinster gemeinsamer Nenner")
- dass das Aussehen und die Bedienbarkeit ("Look and Feel", LaF) einer graphischen Benutzeroberfläche jeweils
systemspezifisch ist. Die einzelnen GUI-Komponenten werden in der durch das jeweilige Betriebssystems vorge-
gebenen Art und Weise dargestellt.
Die Swing -Klassen
◇ Framework zur Erstellung von GUI-Anwendungen mit erweiterter Funktionalität.
Beim JDK 1.1 als Add-On verfügbar, seit dem JDK 1.2 fester Bestandteil der Java 2 Platform.
◇ Die Swing-Klassen bauen auf dem AWT auf, nutzen vieler seiner Grundfunktionalitäten, u.a. das Model und die
Klassen für die Ereignisbearbeitung, sowie die Klassen zur Gestaltung der GUI-Komponenten.
◇ Die Implementierung der Klassen für die GUI-Komponenten – ausser den Top-Level-Containern – greift nicht mehr auf
die Komponentendarstellung des Betriebssystems zurück. Sie ist vielmehr – unter Verwendung graphischer Primitiv-
Operationen ("lightweight components") vollkommen in Java realisiert. Das bedeutet, das das "Look and Feel" einer mit
Swing-Komponenten realisierten GUI unabhängig vom jeweiligen Betriebssystem und damit für alle Systeme gleich
ist.
◇ Andererseits kann der Programmierer und gegebenenfalls auch der Programmbenutzer das LaF einer GUI-Anwendung
selbst festlegen (Pluggable Look and Feel), wobei zwischen einigen Standard-LaFs ausgewählt werden aber auch ein
eigenes LaF gestaltet werden kann. Es ist sogar möglich das LaF dynamisch während des Programmlaufs zu verän-
dern. Defaultmäßig ist für alle GUI-Komponenten ein Java Look and Feel (Name "Metal") eingestellt.
◇ AWT- und Swing-Klassen für GUI-Komponenten dürfen nicht miteinander gemischt verwendet werden.
4
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 522 – 00 – TH – 03
------------------------------------------------------------------------------------
Java Foundation Classes – Überblick (2)
Hierarchie der JFC-Klassen für GUI-Komponenten (unvollständig)
MenuComponent
MenuItem
MenuBar
Menu
CheckBoxMenuItem
PopupMenu
AWT Swing Component
Container
Label
Button
Checkbox
… weitere AWT- Komponenten
Panel
Window
ScrollPane
JComponent
Applet
JApplet
Dialog
Frame
JWindow
JDialog
JFrame
FileDialog
JPanel
JComboBox
JMenuBar
JList
Box
JTable
JScrollPane
JPopupMenu
JToolBar
. . .
. . .
. . .
AbstractButton
JTextComponent
JButton
JToggleButton
JCheckBox
JRadioButton
JMenuItem
JTextArea
JTextField
JEditorPane
JMenu
JCheckBoxMenuItem
JPasswordField
… weitere Swing- Komponenten
JTextPane
JRadioButtonMenuItem
. . .
JLabel
Box.Filler
5
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 523 – 00 – TH – 03
------------------------------------------------------------------------------------
Java Foundation Classes – Überblick (3)
Top-Level-Container
Elementare Komponenten (Auswahl)
"Innere" Container (Auswahl)
AWT Swing Fenster mit Rahmen und Titelleiste Frame JFrame Fenster ohne Rahmen und Titelleiste Window JWindow Dialog-Box Dialog JDialog Applet Applet JApplet
AWT Swing Beschriftung Label JLabel Zeichenfläche Canvas Schaltknopf Button JButton Umschaltknopf (Schaltknopf mit zwei Zuständen) JToggleButton Auswahlfeld Checkbox JCheckBox Gruppe alternativer Auswahlfelder Checkbox JRadioButton
(nur ein Feld kann ausgewählt werden) in Verbindung mit in Verbindung mit CheckboxGroup ButtonGroup Auswahlliste List JList aufklappbare Auswahlliste Choice JComboBox einzeiliges Textfeld (editierbar) TextField JTextField mehrzeiliges Textfeld (editierbar) TextArea JTextArea Bildlaufleiste Scrollbar JScrollBar Bildlauffläche (horizontale u. vertikale Bildlaufleiste) ScrollPane JScrollPane Tabelle JTable Menüeintrag MenuItem JMenuItem
AWT Swing Gruppierungsfeld Panel JPanel Gruppierungbox (festliegender Layout-Manager) Box Menüleiste MenuBar JMenuBar Menu Menu JMenu Werkzeugleiste JToolBar
6
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 524 – 00 – TH – 03
-----------------------------------------------------------------------------------
Java Foundation Classes – Überblick (4)
Einige Swing-Komponenten (Java Look and Feel) (Klasse SwingCompDemo)
7
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 531 – 00 – TH – 04
------------------------------------------------------------------------------------
Basisklassen der JFC-Hierachie (1)
Die abstrakte Klasse Component
◇ Diese – im Package java.awt enthaltene – Klasse steht an der Spitze der Hierarchie der GUI-Komponenten-
Klassen.
Sie definiert grundlegende Methoden, die in fast allen AWT- und Swing-Komponenten-Klassen zur Verfügung
stehen.
Lediglich die AWT-Klassen für Menü-Komponenten befinden sich in einer hiervon unabhängigen Klassen-Hierarchie.
◇ Einige wesentliche Methoden :
(die Methoden zum Registrieren von Listener-Objekten für die Event-Behandlung sind nicht mit aufgeführt )
public void setBackground(Color c) Setzen der Hintergrund-Farbe auf c
public void setForeground(Color c) Setzen der Vordergrund-Farbe auf c
public void setFont(Font f) Setzen der in der Komponente verwendeten Schriftart
public void setSize(int w, int h) Setzen der Breite (auf w) und Höhe (auf h) der Komponente
(Angabe in Pixel)
public void setLocation(int x, int y) Setzen der Position der Komponente
(linke obere Ecke auf (x,y), Angabe in Pixel)
public void setVisible(boolean b) Anzeigen / Verbergen der Komponente
(b==true : Komponente sichtbar, sonst unsichtbar)
public void setEnabled(boolean b) Aktivierung / Deaktivierung der Reaktion der Komponente auf
Benutzereingaben (b==true : Komponente kann auf
Benutzereingaben reagieren (Events erzeugen))
Defaultmässig sind alle Komponenten aktiviert
public Color getBackground() Rückgabe der Hintergrund-Farbe
public Color getForeground() Rückgabe der Vordergrund-Farbe
public Font getFont() Rückgabe der verwendeten Schriftart
public int getWidth() Rückgabe der aktuellen Breite der Komponente (in Pixel)
public int getHeight() Rückgabe der aktuellen Höhe der Komponente (in Pixel)
public boolean isVisable() Rückgabe des Sichtbarkeits-Status der Komponente
true, wenn Komponente sichtbar, false, wenn nicht
public boolean isEnabled() Rückgabe des Aktivierungs-Status der Komponente
true, wenn Komponente aktiviert, false, wenn nicht
public void paint(Graphics g) Zeichnen der Komponente unter Verwendung des Graphik-
Context-Objekts g.
Wird vom System aufgerufen (Callback), z.B. wenn die Kom-
ponente erstmals sichtbar gemacht wird oder eine Zustands-
(z.B. Größen-) änderung erfolgt ist
public void repaint() Aufforderung an das System, die Komponente neu zu zeichnen
(mittels paint())
Kann vom Anwender-Code aufgerufen werden, wenn sich der
Zustand des GUI-Objekts geändert hat.
public void validate() Sicherstellung, dass die Komponente ein gültiges Layout hat
(Diese Methode ist insbesondere für Container vorgesehen)
public void requestFocusInWindow() Anforderung des Focus (wenn Top-Level-Cont. Focus besitzt )
8
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 532 – 00 – TH – 03
------------------------------------------------------------------------------------
Basisklassen der JFC-Hierachie (2)
Die Klasse Container
◇ Diese – im Package java.awt definierte – Klasse ist die Basisklasse aller GUI-Container-Klassen.
Auch die Klassen für einfache Swing-Komponenten sind – indirekt – von dieser Klasse abgeleitet.
Sie ist selbst von der Klasse Component abgeleitet.
◇ Sie stellt – über die von Component geerbten und teilweise überschriebenen Methoden hinaus – insbesondere
Methoden zur Verfügung, die das Verwalten (z.B. Einfügen, Entfernen) von GUI-Komponenten ermöglichen.
◇ Die in einem GUI-Container-Objekt enthaltenen GUI-Komponenten werden in einer Liste verwaltet, wobei die Reihen-
folge der Listenelemente standardmässig durch die Reihenfolge ihres Einfügens festgelegt ist.
Diese Reihenfolge bestimmt auch die Anordnungs-Reihenfolge der Komponenten entsprechend des jeweils festgeleg-
ten Layout-Managers.
Es ist aber auch möglich, die Reihenfolge der Komponenten (Position bezüglich des gewählten Layouts) durch einen
entsprechenden Parameter ("Index") der Einfüge-Methode explizit zu beeinflussen.
◇ Wenn in einen Container eine Komponente neu eingefügt oder entfernt wird, nachdem der Container bereits sichtbar
ist, muß die von Component geerbte – aber überschriebene – Methode validate() aufgerufen werden.
Dadurch wird der Layout-Manager des Containers veranlasst, das Layout entsprechend anzupassen.
◇ Die von Component geerbte Methode paint() ist so überschrieben, dass für alle im Container enthaltenen
Komponenten deren paint()-Methode aufgerufen wird.
◇ Die wichtigsten Methoden zur Komponentenverwaltung sind :
(die Methoden zum Registrieren von Listener-Objekten für die Event-Behandlung sind nicht mit aufgeführt )
◇ Ein Container besitzt Randbereiche (insets), die nicht für die Aufnahme von Komponenten zur Verfügung stehen
(z.B. die Titelleiste).
Die Randbereiche werden in einem Objekt der Klasse Insets (Package java.awt) zusammengefasst.
Die 4 Randbereiche (Angabe in Pixel) sind zugänglich über public-int-Datenkomponenten : top, left, bottom, right.
Zur Ermittlung des Insets-Objekt eines Containers dient die Memberfunktion :
public Insets getInsets() Ermittlung der Randbereiche des Containers
public Component add(Component comp) Einfügen der Komponente comp am Ende des Containers
public Component add(Component comp, Einfügen der Komponente comp an der Position idx int idx)
public Component add(Component comp, Einfügen der Komponente comp unter Berücksichtigung
Object constr) der durch constr festgelegten Einschränkungen
public Component getComponent(int idx) Ermitteln der Komponente an der Position idx
public Component[] getComponents() Ermitteln aller Komponenten des Containers
public int getComponentCount() Ermitteln der Anzahl der Komponenten im Container
public void remove(Component comp) Entfernen der Komponente comp aus dem Container
public void remove(int idx) Entfernen der Komponente an der Position idx
public void removeAll() Entfernen aller Komponenten aus dem Container
public void setLayout(LayoutManager mgr) Setzen des Layout-Managers mgr für den Container
public LayoutManager getLayout() Ermitteln des Layout-Managers des Containers
9
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 533 – 00 – TH – 03
-----------------------------------------------------------------------------------
Basisklassen der JFC-Hierachie (3)
Die abstrakte Klasse JComponent
◇ Diese von Container abgeleitete und im Package javax.swing enthaltene Klasse ist Basisklasse aller
Swing-Komponenten-Klassen mit Ausnahme der Top-Level-Container
◇ Die Klasse passt einige der von Container und Component geerbten Methoden an die Funktionalität und
die speziellen Eigenschaften des Swing-Frameworks an.
Zusätzlich definiert sie Methoden, die speziell für Swing-Komponenten von Bedeutung sind
◇ U.a. besitzen Swing-Komponenten die folgenden bei AWT-Komponenten nicht vorhandenen Besonderheiten :
▻ Swing-Komponenten können mit einer Umrandung versehen werden.
Die Umrandung wird durch ein Objekt einer das Interface Border implementierenden Klasse festgelegt.
Zur Erzeugung derartiger Border-Objekte stehen statische Methoden der Klasse BorderFactory zur
Verfügung.
▻ Der Hintergrund von Swing-Komponenten kann durchsichtig (nicht-opak) oder undurchsichtig (opak) sein.
AWT-Komponenten besitzen immer einen undurchsichtigen Hintergrund.
In der Klasse JComponent ist als Default durchsichtig (nicht-opak) festgelegt.
Allerdings hängt der tatsächliche Defaultwert dieser Eigenschaft bei den abgeleiteten Swing-Klassen i.a. von
dem jeweils eingesetzten LaF ab.
▻ Swing-Komponenten können mit einem Tooltip ausgestattet werden. Hierbei handelt es sich um einen mit der
Komponente verknüpften Hinweistext, der angezeigt wird, wenn der Mauszeiger für kurze Zeit über der Kom-
ponente verweilt.
▻ Für Swing-Komponenten können die dem Layout-Manager als Dimensionierungsvorschläge dienenden Werte
für die maximale, die minimale und die bevorzugte Größe (Breite und Höhe) der Komponente sowie Vorschläge
für die Ausrichtung einer Komponente (in x- und y-Richtung) explizit gesetzt werden. Die entsprechenden Ermitt-
lungs-Methoden (get...(), z.B. getMaximumSize()) sind bereits in der Klasse Component definiert.
◇ Zu den wichtigsten der speziellen Swing-Komponenten-Methoden gehören :
(die Methoden zum Registrieren von Listener-Objekten für die Event-Behandlung sind nicht mit aufgeführt )
public void setBorder(Border bord) Setzen des Border-Objekts bord als Umrandung für
die Komponente
public Border getBorder() Ermitteln der Umrandung der Komponente
public void setOpaque(boolean opa) Setzen des Hintergrunds der Komponente auf undurch-
sichtig (opa==true) bzw durchsichtig (opa==false)
public boolean isOpaque() Ermitteln, ob Hintergrund der Komponente undurchsichtig
oder durchsichtig ist
true, wenn undurchsichtig, false, wenn durchsichtig
public void setToolTipText(String txt) Setzen des Tooltip-Textes für die Komponente
public String getToolTipText() Ermitteln des Tooltip-Textes der Komponente
public void setMaximumSize(Dimension d) Setzen der maximalen Größe der Komponente auf die
durch d gegebene Breite und Höhe.
Erzeugung eines Dimension-Objekts : new Dimension(breite, hoehe)
public void setMinimumSize(Dimension d) Setzen der minimalen Größe der Komponente auf d
public void setPreferredSize(Dimension d) Setzen der bevorzugten Größe der Komponente auf d
public void setAlignmentX(float align) Setzen der Ausrichtung in hor. Richtung (0.0 ... 1.0)
public void setAlignmentY(float align) Setzen der Ausrichtung in vert. Richtung (0.0 ... 1.0)
10
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 541 – 00 – TH – 04
------------------------------------------------------------------------------------
Erstellung einer GUI-Anwendung in Java (1)
Prinzipielle Vorgehensweise
◇ Jede GUI-Anwendung besitzt wenigstens ein Top-Level-Fenster, über das sie mit dem Anwender kommuniziert.
Eine GUI-Anwendung kann auch mehrere Top-Level-Fenster besitzen.
◇ Für jedes Top-Level-Fenster wird eine eigene Klasse definiert.
Der Aufbau dieser Fenster-Erzeugungs-Klasse kann unterschiedlich sein.
Neben anderen bieten sich folgende Hauptvarianten an :
▻ Die Klasse instanziert ein Objekt der eingesetzten JFC-Top-Level-Container-Klasse (i.a. in ihrem Konstruktor)
Dieses kann sie gegebenenfalls über eine Datenkomponente referieren.("has a container")
▻ Die Klasse ist von der eingesetzten JFC-Top-Level-Container-Klasse abgeleitet.
Bei der Instanzierung der Klasse wird das Top-Level-Container-Objekt als Teilobjekt angelegt ("is a container").
◇ Für normale Anwendungsprogramme werden als Top-Level-Container-Klassen i.a. die Klassen Frame (für AWT-
Anwendungen) bzw JFrame (für Swing-Anwendungen) eingesetzt.
◇ Die Konfigurierung eines Top-Level-Fensters und damit der graphischen Oberfläche erfolgt typischerweise im
Konstruktor der Fenster-Erzeugungs-Klasse bzw in speziellen von diesem aufgerufenen Memberfunktionen :
▻ Gegebenenfalls explizite Erzeugung des Top-Level-Container-Objekts (s. oben)
▻ Festlegung des Erscheinungsbildes (ohne LaF, das wird i.a. von ausserhalb , z.B in der main()-Methode der
Start-Klasse, festgelegt) :
▹ Setzen des Layout-Managers (wenn anders als Default)
▹ Setzen der Hintergrund- und Vordergrundfarbe (wenn anders als Default)
▹ Setzen der Schriftart (wenn überhaupt benötigt und anders als Default)
▹ Setzen der (Ausgangs-)Größe des Fensters
Wenn die Fenster-Erzeugungs-Klasse von der Top-Level-Container-Klasse abgeleitet ist, wird das auch
häufig von ausserhalb – nach der Instanziierung der Klasse – vorgenommen.
▹ Setzen des Titels des Fensters
Dieser kann entweder dem Konstruktor der Klasse Frame bzw JFrame übergeben werden oder
mittels der Memberfunktion setTitle() festgelegt werden.
Auch dies erfolgt häufig von ausserhalb des Konstruktors der Fenster-Erzeugungs-Klasse, wenn diese von der
Top-Level-Container-Klasse abgeleitet ist.
▻ Erzeugen, Konfigurieren und Einfügen der Komponenten-Objekte des Containers.
Dies wird sinnvollerweise haeufig in eine eigene Methode ausgelagert.
Zur Konfigurierung einer einzufügenden GUI-Komponente sind gegebenenfalls analoge Schritte wie bei der
Konfigurierung des Top-Level-Fensters auszuführen.
Je nach Komponente stehen u.U. noch zusätzliche Konfigurationsmöglichkeiten zur Verfügung (z. B. Setzen
einer Umrandung) Anmerkung zum Einfügen der Komponenten:
In die AWT-Top-Level-Container (Frame, Dialog, Window) werden Komponenten direkt eingefügt
(mittels add()).
In die Swing-Top-Level-Container ( JFrame, JDialog, JWindow) dagegen werden die Komponenten
nicht direkt eingefügt. Sie verfügen über einen speziellen Einfüge-Container, die sogenannte content pane, in die
alle aufzunehmenden Komponenten mittels add() einzufügen sind.
◇ Definition von Event-Listener-Klassen und Registrierung der Event-Listener-Objekte bei den einzelnen
Komponenten. Dies wird ebenfalls sinnvollerweise haeufig in eine eigene Methode ausgelagert.
Die Kommunikation mit dem Anwender und dem Rest des Anwendungsprogramms (Entity-Klassen) erfolgt nur
über die durch die Event-Listener definierten Methoden (Callbacks !)
◇ Anzeigen des Top-Level-Containers (und aller in ihm enthaltenen Komponenten).
Dies erfolgt durch Einschalten der Sichtbarkeit des Containers (Aufruf von setVisible(true)).
Dies kann entweder ebenfalls im Konstruktor der Fenster-Erzeugungs-Klasse oder – wenn diese von der Top-Level-
Container-Klasse abgeleitet ist – von ausserhalb erfolgen.
11
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 542 – 00 – TH – 01
-----------------------------------------------------------------------------------
Erstellung einer GUI-Anwendung in Java (2)
Beispiel einer sehr einfachen AWT-Anwendung
Top-Level-Fenster (abgeleitet von Frame) mit einer Label-Komponente
// AWTSimpleFrame.java
import java.awt.*;
public class AWTSimpleFrame extends Frame
{
public AWTSimpleFrame(String title)
{
super(title);
Label lab1 = new Label("Hallo !", Label.CENTER);
add(lab1);
addWindowListener(new WindowClosingAdapter()); // Registrierung eines
// Event-Listeners
// zum Schliessen des Fensters
setSize(300,160);
}
public static void main(String[] args)
{
AWTSimpleFrame fenster = new AWTSimpleFrame("Ein sehr einfaches AWT-Fenster");
fenster.setVisible(true);
}
}
12
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 543 – 00 – TH – 01
-----------------------------------------------------------------------------------
Erstellung einer GUI-Anwendung in Java (3)
Beispiel einer sehr einfachen Swing-Anwendung
Top-Level-Fenster (abgeleitet von JFrame) mit einer JLabel-Komponente
// SwingSimpleFrame.java
import javax.swing.*;
import java.awt.*;
public class SwingSimpleFrame extends JFrame
{
private Container c;
public SwingSimpleFrame(String title)
{
super(title);
JLabel lab1 = new JLabel("Hallo !", SwingConstants.CENTER);
c = getContentPane();
c.add(lab1);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(320, 160);
}
public static void main(String[] args)
{
SwingSimpleFrame fenster = new SwingSimpleFrame(
"Ein sehr einfaches Swing-Fenster");
fenster.setVisible(true);
}
}
13
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 551 – 00 – TH – 03
------------------------------------------------------------------------------------
Die Klasse Color (Package java.awt)
Allgemeines
◇ Objekte der Klasse Color dienen zur Beschreibung von Farben.
Sie werden z.B. zum Setzen der Hintergrund- und Vordergrundfarbe von GUI-Komponenten benötigt
◇ Objekte dieser Klasse legen eine Farbe durch deren Rot- Grün- und Blau-Anteile (RGB-Werte) fest.
Jeder Anteil wird durch einen int-Wert im Bereich 0 ... 255 repräsentiert. Er lässt sich auch durch einen
float-Wert im Bereich 0.0 ... 1.0 angeben.
◇ Eine weitere Datenkomponente dient zur Beschreibung der Farb-Transparenz (Alpha-Wert).
Auch dieser Wert wird entweder als int-Wert (Bereich 0 ... 255) oder als float-Wert (Bereich 0.0 ...
1.0) angegeben.
Dabei bedeutet
- der Wert 0 bzw 0.0 vollkommen durchsichtig (nicht opak),
- der Wert 255 bzw 1.0 vollkommen undurchsichtig (opak)
◇ Objekte für 13 häufig verwendete Farben sind vordefiniert und stehen als Klassen-Konstante zur Verfügung :
Von Color.BLACK über Color.GREEN bis Color.YELLOW
Konstruktoren
◇ Beliebige Color-Objekte lassen sich unter Angabe der RGB-Werte und gegebenenfalls des Alpha-Werts mit Hilfe
der folgenden Konstruktoren erzeugen:
Memberfunktionen zur Ermittlung der Farb-Komponenten
◇ Neben zahlreichen anderen Memberfunktionen existieren die folgenden Methoden zum Ermitteln der einzelnen
Farbkomponenten eines Color-Objekts.
public Color(int r, int g, int b) Erzeugung eines Color-Objekts mit den angegebenen
RGB-Werten und einem Alpha-Wert von 255
(vollkommen undurchsichtig)
public Color(float r, float g, float b) Erzeugung eines Color-Objekts mit den angegebenen
RGB-Werten und einem Alpha-Wert von 1.0
(vollkommen undurchsichtig)
public Color(int r, int g, int b, Erzeugung eines Color-Objekts mit den angegebenen
int a) RGB-Werten und dem angegebenen Alpha-Wert (a)
public Color(float r, float g, float b, Erzeugung eines Color-Objekts mit den angegebenen
float a) RGB-Werten und dem angegebenen Alpha-Wert (a)
public int getRed() Ermittlung der Rot-Komponente im Bereich 0 ... 255
public int getGreen() Ermittlung der Grün-Komponente im Bereich 0 ... 255
public int getBlue() Ermittlung der Blau-Komponente im Bereich 0 ... 255
public int getAlpha() Ermittlung des Alpha-Werts im Bereich 0 ... 255
14
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 552 – 00 – TH – 02
-----------------------------------------------------------------------------------
Die Klasse Font (Package java.awt)
Allgemeines
◇ Objekte der Klasse Font repräsentieren Schriftarten.
◇ Die Methode setFont() der Klasse Component dient zur Festlegung der in einer GUI-Komponente zu ver-
wendenden Schriftart. Ihr ist ein Font-Objekt als Parameter zu übergeben.
Wird für eine GUI-Komponente keine Schriftart explizit festgelegt (kein Aufruf der Methode setFont() oder
ein Aufruf mit null als aktuellem Parameter), so erbt diese Komponente die in ihrem Container eingesetzte Schriftart.
Defaultmässig wird ein systemabhängiger Standard-Font verwendet.
◇ Eine Schriftart wird durch drei Parameter festgelegt :
▻ Font-(Familien-)Name
▻ Schriftstil
▻ Schriftgröße
◇ Font-(Familien-)Name Als Font-(Familien-)Name wird i.a. ein Name für einen logischen Font angegeben, der von der Java-Laufzeitumgebung
auf einen im System real vorhandenen Font (physikalischen Font) abgebildet wird.
Von jedem Java-System werden die folgenden logischen Font-Familien-Namen unterstützt :
▻ "Serif" systemspezifische Proportionalzeichensatz-Familie TimesRoman
Umsetzung unter Windows : True-Type-Font Times New Roman
▻ "SansSerif" systemspezifische Proportionalzeichensatz-Familie Helvetica
Umsetzung unter Windows : True-Type-Font Arial
▻ "Monospaced" systemspezifische Nichtproportionalzeichensatz-Familie Courier
Umsetzung unter Windows : True-Type-Font Courier New
◇ Schriftstil
Spezifizierung durch einen int-Wert. Hierfür sind in der Klasse Font die folgenden Konstanten definiert :
▻ Font.PLAIN (0) normale Schrift
▻ Font.BOLD (1) fette Schrift
▻ Font.ITALIC (2) kursive Schrift Die Schriftstile Font.BOLD und Font.ITALIC können auch miteinander kombiniert werden (Addition oder
bitweis-Oder) fette und kursive Schrift.
◇ Schriftgröße
Angabe in Punkt (Pt) durch einen int-Wert. Übliche Punktgrößen für normale Textdarstellung : 10 oder 12 Pt.
Konstruktor
◇ Font-Objekte können mit Hilfe des folgenden Konstruktors erzeugt werden :
Memberfunktionen zur Ermittlung der Font-Komponenten
◇
public Font(String name, int style, int size) Erzeugung eines neuen Font-Objekts mit dem
Namen name, Stil style und Größe size
public String getName() Ermittlung des logischen Font-Familien-Namens
public String getFamily() Ermittlung des physikalischen Font-Familien-Namens
public int getStyle() Ermittlung des Schriftstils
public int getSize() Ermittlung der Schriftgröße in Punkt
15
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 553 – 01 – TH – 04
-----------------------------------------------------------------------------------
Layout-Manager in Java (1)
Allgemeines
◇ Üblicherweise wird die Anordnung (Größe und Position) der in einem Container enthaltenen Komponenten durch
einen Layout-Manager vorgenommen.
Prinzipiell können die einzelnen Komponenten zwar "Hinweise" zu ihrer Größe, Position und Ausrichtung enthalten,
diese müssen aber nicht vom Layout-Manager berücksichtigt werden. Vielmehr hat dieser das "letzte Wort" bezüglich
der Anordnung.
◇ Es ist auch möglich, auf einen Layout-Manager zu verzichten und mit absoluter Positionierung zu arbeiten. Dies erfor-
dert dann eine genaue Festlegung der Größe und der Position jeder einzelnen Komponente und führt zu Anpassungs-
problemen, wenn die Größe des Top-Level-Containers bzw die Ausführungs-Plattform verändert wird
◇ Ein Layout-Manager ist ein Objekt einer Klasse, die das Interface LayoutManager (Package java.awt)
implementiert.
Dieses Interface definiert Methoden, die für die Anordnung von GUI-Komponenten innerhalb eines Containers benötigt
werden.
◇ Für erweiterte Layout-Fähigkeiten ist das von LayoutManager abgeleitete Interface LayoutManager2
definiert. Es enthält Methoden, die es einem Layout-Manager ermöglichen, durch contraints-Objekte festgelegte Anord-
nungs-Beschränkungen / -Vorgaben explizit zu berücksichtigen.
contraints-Objekte (häufig String-Objekte) spezifizieren wie und wo Komponenten in das Layout einzufügen sind.
◇ Die Java-Bibliothek stellt eine Reihe von Layout-Manager-Klassen zur Verfügung.
Die einzelnen Klassen unterscheiden sich insbesondere hinsichtlich der Unterteilung der Gesamtfläche eines Containers
in verschiedene Bereiche und die Zuordnung dieser Bereiche zu den im Container enthaltenen Komponenten. Einige
Layout-Manager passen dabei die Komponenten in ihrer Groesse an oder fügen Zwischenräume zwischen ihnen ein.
Einige von ihnen implementieren nur das Interface LayoutManager, andere das Interface LayoutManager2.
Layout-Manager-Klassen sind sowohl im Package java.awt als auch im Package javax.swing definiert Die am häufigsten verwendeten Layout-Manager-Klassen sind :
▻ BorderLayout (Package java.awt)
▻ FlowLayout (Package java.awt)
▻ GridLayout (Package java.awt)
▻ BoxLayout (Package javax.swing)
▻ GridBagLayout (Package java.awt)
◇ Defaultmässig ist in den meisten GUI-Container-Klassen das BorderLayout eingestellt.
Ausnahmen :
- Für die Klassen Panel und JPanel ist FlowLayout voreingestellt.
- Für die Klasse Box (Package javax.swing) ist BoxLayout voreingestellt Ein anderer Layout-Manager kann mit der in der Klasse Container definierten Methode void setLayout(LayoutManager mgr) für jedes Container-Objekt individuell festgelegt werden Dabei lassen sich die im Package javax.swing definierten Layout-Manager-Klassen nur für Swing-Komponenten
einsetzen, während die im Package java.awt enthaltenen Layout-Manager-Klassen sowohl für AWT- als auch
für Swing-Komponenten Anwendung finden.
16
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 553 – 02 – TH – 02
-----------------------------------------------------------------------------------
Layout-Manager in Java (2)
Die Klasse BorderLayout (Package java.awt)
◇ Dieser Layout-Manager teilt den Container in fünf Gebiete ein : "Norden", "Süden", "Westen", Osten" und "Zentrum".
In jedes dieser Gebiete kann er genau eine Komponente einfügen.
◇ Die einzelnen Komponenten werden in ihrer Größe so angepasst, dass sie insgesamt den gesamten Container ausfüllen.
Allerdings können sowohl horizontale als auch vertikale Abstände zwischen den Komponenten festgelegt werden. Die Komponenten im "Norden" und "Süden" bekommen ihre bevorzugte Höhe und werden in der Breite an die Con-
tainergröße angepasst
Die Komponenten im "Westen" und "Osten" bekommen dagegen ihre bevorzugte Breite und werden in der Höhe an den
Container angepasst.
Die Komponente im "Zentrum" wird sowohl in der Höhe als auch in der Breite an den verbleibenden Bereich angepasst.
◇ Konstruktoren :
◇ Beim Einfügen einer Komponente in einen Container (mittels add()) ist üblicherweise das Gebiet, in dem sie platziert
werden soll, anzugeben.
Für diese Angabe sind die folgenden in der Klasse BorderLayout definierten (String-)Konstanten zu verwenden :
- BorderLayout.NORTH
- BorderLayout.SOUTH
- BorderLayout.WEST
- BorderLayout.EAST
- BorderLayout.CENTER Beispiel : Panel p = new Panel(); p.setLayout(new BorderLayout());
p.add(new Button("Okay"), BorderLayout.SOUTH); Wird keine Gebietsangabe beim Einfügen angegeben, wird die Komponente im "Zentrum" platziert.
◇ Wird die Größe des Containers geändert (z.B. durch Ziehen mit der Maus), so bleibt die Höhe der Komponenten im
"Norden" und "Süden" sowie die Breite der Komponenten im "Westen und "Osten" unverändert, während die jeweils
andere Dimension dieser Komponenten sowie beide Dimensionen der Komponente im "Zentrum" an die Größe des
Containers angepasst werden.
◇ Beispiel : Border-Layout eines JFrame-Containers mit fünf JButton-Komponenten
public BorderLayout() Erzeugung eines BorderLayout-Objekts, das die Kom-
ponenten ohne Zwischenabstände anordnet
public BorderLayout(int hgap, int vgap) Erzeugung eines BorderLayout-Objekts, das die Kom-
ponenten mit dem horizontalen Abstand hgap und dem
vertikalen Abstand vgap anordnet (Abstaende in Pixel)
17
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 553 – 03 – TH – 01
-----------------------------------------------------------------------------------
Layout-Manager in Java (3)
Demonstrationsbeispiel zu Layout-Manager (hier : BorderLayout)
// LayoutDemo.java
import java.awt.*;
import javax.swing.*;
public class LayoutDemo extends JFrame
{
Container c;
JButton[] ba;
String titel;
public LayoutDemo()
{
c=getContentPane();
titel = "LayoutDemo : ";
ba = new JButton[5];
for (int i=0; i<ba.length; i++)
{
ba[i] = new JButton("Button "+(i+1));
ba[i].setAlignmentX(Component.CENTER_ALIGNMENT);
}
ba[2].setText(ba[2].getText()+" with long title");
ba[2].setFont(new Font("Serif", Font.ITALIC|Font.BOLD, 12));
ba[2].setBackground(Color.ORANGE);
useBorderLayout();
//useFlowLayout();
//useGridLayout();
//useBoxLayout();
setTitle(titel);
setSize(300, 170);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void useBorderLayout() // BorderLayout ist Default bei JFrame
{ c.add(ba[0], BorderLayout.NORTH);
c.add(ba[1], BorderLayout.SOUTH);
c.add(ba[2], BorderLayout.CENTER);
c.add(ba[3], BorderLayout.WEST);
c.add(ba[4], BorderLayout.EAST);
titel+="BorderLayout";
}
private void useFlowLayout()
{ //
}
private void useGridLayout()
{ //
}
private void useBoxLayout()
{ //
}
public static void main(String[] args)
{
new LayoutDemo().setVisisble(true);
}
}
18
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 553 – 04 – TH – 02
-----------------------------------------------------------------------------------
Layout-Manager in Java (4)
Die Klasse FlowLayout (Package java.awt)
◇ Dieser Layout-Manager fügt die Komponenten "fliessend" zeilenweise von links nach rechts in den Container ein.
Dabei bedeutet "fliessend", dass die Komponenten solange in der Reihenfolge ihres Einfügens nebeneinander platziert
werden, bis kein Platz mehr für die nächste Komponente vorhanden ist. Dann wird das Einfügen analog in der nächsten
Reihe fortgesetzt.
◇ Die Komponenten werden in ihrer bevorzugten Größe (Breite und Höhe) dargestellt. Defaultmässig werden die in einer Reihe befindlichen Komponenten zentriert ausgerichtet.
Zwischen den Komponenten wird sowohl horizontal als auch vertikal ein Abstand von 5 Pixel gesetzt.
Der vertikale Abstand bezieht sich dabei auf die Komponenten mit der jeweils größten Höhe. Sowohl die Ausrichtung als auch der Abstand in beiden Richtungen können geändert werden.
◇ Konstruktoren :
◇ Zur Angabe der Komponenten-Ausrichtung in den einzelnen Zeilen (Konstruktor-Parameter align) stehen in der
Klasse FlowLayout die folgenden Konstanten zur Verfügung :
- FlowLayout.LEFT (Ausrichtung linksbündig)
- FlowLayout.RIGHT (Ausrichtung rechtsbündig)
- FlowLayout.CENTER (Ausrichtung zentriert, default)
◇ Wird die Größe des Containers geändert (z.B. durch Ziehen mit der Maus), so wird die Zuordnung der Komponen-
ten zu den einzelnen Zeilen entsprechend angepasst.
◇ Beispiel : Flow-Layout eines JFrame-Containers mit fünf JButton-Komponenten
(Ergänzung / Modifikation des obigen Demonstrationsprogramms)
public FlowLayout() Erzeugung eines FlowLayout-Objekts, mit den Default-
einstellungen (zentrierte Ausrichtung und vertikaler und
horizontaler Abstand von 5 Pixel)
public FlowLayout(int align) Erzeugung eines FlowLayout-Objekts, mit einer durch
align festgelegten Ausrichtung und einem vertikalen und
horizontalen Abstand von 5 Pixel
public FlowLayout(int align, int hgap, Erzeugung eines FlowLayout-Objekts, mit einer durch
int vgap) align festgelegten Ausrichtung und einem durch hgap
(horizontal) und vgap (vertikal) gegebenen Abstand
private void useFlowLayout()
{ c.setLayout(new FlowLayout());
for (int i=0; i<ba.length; i++)
c.add(ba[i]);
titel+="FlowLayout";
}
19
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 553 – 05 – TH – 02
-----------------------------------------------------------------------------------
Layout-Manager in Java (5)
Die Klasse GridLayout (Package java.awt)
◇ Dieser Layout-Manager teilt die Containerfläche in gitter- bzw tabellenartig angeordnete Zellen auf.
Die Zellen sind Rechtecke gleicher Größe. Diese Größe ergibt sich aus der Containergröße und der Anzahl von Zeilen
und Spalten. In jedem dieser Rechtecke wird genau eine Komponente platziert.
Standardmässig (horizontale Ausrichtung,von links nach rechts) werden die Komponenten in der Reihenfolge ihres
Einfügens zeilenweise von links nach rechts angeordnet.
◇ Die Größe der Komponenten wird an die Zellen-Größe angepasst, so dass der in der Zelle verfügbare Platz voll ausge-
nutzt wird. Alle Komponenten haben somit die gleiche Größe.
Defaultmässig besteht zwischen den Zellen kein Abstand. Es kann aber sowohl ein vertikaler als auch ein horizontaler
Abstand festgelegt werden.
◇ Die Anzahl der Zeilen und Spalten können angegeben werden (im Konstruktor oder mittels Memberfunktionen).
Wenigstens einer der beiden Werte muss von 0 verschieden sein. Der Wert 0 bedeutet "beliebig viele".
Wenn beide Werte von 0 verschieden sind, wird der Wert für die Anzahl der Spalten ignoriert. In diesem Fall wird
die tatsächliche Anzahl der Spalten aus der festgelegten Anzahl der Zeilen und der Komponenten-Anzahl ermittelt.
Die explizite Angabe einer Spalten-Anzahl beeinflusst das Layout nur dann, wenn für die Anzahl der Zeilen 0 angege-
ben wird. Wird weder die Anzahl der Zeilen noch die Anzahl der Spalten explizit festgelegt, wird die Zeilenzahl
defaultmässig auf 1 gesetzt. Die Anzahl der Spalten ergibt sich dann aus der Anzahl der Komponenten.
◇ Konstruktoren :
◇ Wird die Größe des Containers geändert (z.B. durch Ziehen mit der Maus), so wird – bei gleichbleibender Zeilen-
und Spaltenzahl – die Größe der Zellen und damit die Größe der Komponenten an die jeweilige Gesamtgröße des
Containers angepasst.
◇ Beispiel : Grid-Layout eines JFrame-Containers mit fünf JButton-Komponenten (3 Zeilen, 2 Spalten)
(Ergänzung / Modifikation des obigen Demonstrationsprogramms)
public GridLayout() Erzeugung eines GridLayout-Objekts, mit einer Zeile,
beliebig vielen Spalten, kein Abstand zwischen den Zellen
public GridLayout(int rows, int cols) Erzeugung eines GridLayout-Objekts, mit rows Zeilen
und cols Spalten (tatsächliche Auswirkung siehe oben),
kein Abstand zwischen den Zellen
public GridLayout(int rows, int cols, Erzeugung eines GridLayout-Objekts, mit rows Zeilen
int hgap, int vgap) und cols Spalten (siehe oben), sowie einem durch hgap
(horizontal) und vgap (vertikal) gegebenen Zellen-Abstand
private void useGridLayout()
{ c.setLayout(new GridLayout(3,2));
for (int i=0; i<ba.length; i++)
c.add(ba[i]);
titel+="GridLayout(3,2)";
}
20
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 553 – 06 – TH – 02
------------------------------------------------------------------------------------
Layout-Manager in Java (6)
Die Klasse BoxLayout (Package javax.swing)
◇ Dieser Layout-Manager ordnet die Komponenten – gemäß ihrer Einfüge-Reihenfolge - entweder horizontal in einer
Zeile oder vertikal in einer Spalte an. Die Anordnungs-Achse ist jeweils festzulegen (kein Default).
◇ Er berücksichtigt hierbei sowohl die für die einzelnen Komponenten eingestellten Größen-Parameter (minimale, maxi-
male und bevorzugte Größe) als auch deren festgelegte vertikale und horizontale Ausrichtung. Grundsätzlich versucht er die Komponenten in ihrer bevorzugten Größe darzustellen.
Sind bei vertikaler Anordnung die bevorzugten Breiten der Komponenten unterschiedlich, wird versucht, unter Be-
rücksichtigung der jeweiligen maximalen Breiten, die Breite aller Komponenten an die größte bevorzugte Breite anzu-
passen.
Ist das nicht möglich, z.B. weil die maximalen Größen es nicht zulassen, werden die Komponenten in ihrer bevorzugten
Breite dargestellt. Die horizontale Ausrichtung der Komponenten (sowohl untereinander als auch innerhalb des Contai-
ners) richtet sich nach deren – defaultmässig vorgegebener bzw explizit gesetzter – horizontaler (X-) Ausrichtung. Analoges gilt für die horizontale Anordung.
Werden die Komponenten mit unterschiedlicher Höhe dargestellt, richtet sich ihre vertikale Ausrichtung nach der
für die einzelnen Komponenten eingestellten vertikalen (Y-) Ausrichtung (Default ist.i.a. zentriert)
◇ Zwischen den Komponenten wird kein Abstand eingefügt.
Zum Erzeugen von Abständen können spezielle unsichtbare Füll-Komponenten eingesetzt werden.
◇ Konstruktor :
◇ Zur Festlegung der Anordnungs-Achse (Konstruktor-Parameter axis) stehen in der Klasse BoxLayout die folgen-
den Konstanten zur Verfügung :
- BoxLayout.X_AXIS (horizontale Anordnung, in einer Zeile)
- BoxLayout.Y_AXIS (vertikale Anordnung, in einer Spalte)
- BoxLayout.LINE_AXIS (Bedeutung sprachabhängig, bei europäischen Sprachen : horizontale Anordnung)
- BoxLayout.PAGE_AXIS (Bedeutung sprachabhängig, bei europäischen Sprachen : vertikale Anordnung)
◇ Bei einer Größenänderung des Containers (z.B. durch Ziehen mit der Maus), behalten die Komponenten ihre ur-
sprüngliche Größe, Anordnung und Ausrichtung (zueinander und im Container).
◇ Beispiel : Box-Layout eines JFrame-Containers mit fünf JButton-Komponenten (vertikale Anordnung)
(Ergänzung / Modifikation des obigen Demonstrationsprogramms)
public BoxLayout(Container con, int axis) Erzeugung eines BoxLayout-Objekts für das
Container-Objekt con mit der durch axis
festgelegten Anordnungs-Achse
private void useBoxLayout()
{ c.setLayout(new BoxLayout(c, BoxLayout.Y_AXIS));
for (int i=0; i<ba.length; i++)
c.add(ba[i]);
titel+="BoxLayout";
}
21
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 554 – 01 – TH – 04
-----------------------------------------------------------------------------------
Umrandungen für Swing-Komponenten in Java (1)
Umrandungen und das Interface Border (Package javax.swing.border)
◇ Swing-GUI-Komponenten (genauer : Objekte aller von JComponent abgeleiteten Klassen) können mit einer
Umrandung versehen werden.
Derartige Umrandungen können u.a. dazu dienen :
- GUI-Komponenten mit einer Dekoration zu versehen
- um rahmenlose GUI-Komponenten einen Rahmen zu zeichnen
- für GUI-Komponenten einen Namen anzugeben
- GUI-Komponenten mit Abstandsflächen zu versehen.
◇ Umrandungen werden durch Border-Objekte beschrieben.
Zum Setzen einer Umrandung muß die in JComponent definierte Memberfunktion setBorder() mit einem
Border-Objekt als Parameter für das entsprechende GUI-Komponenten-Objekt aufgerufen werden.
◇ Border-Objekte sind Objekte von Klassen, die das Interface Border implementieren.
Klassen für Border-Objekte
◇ In der Java-Standard-Bibliothek – u.a. im Package javax.swing.border – sind zahlreiche Klassen, die das
Interface Border implementieren, definiert.
Einige der im Package javax.swing.border enthaltenen Klassen sind :
▻ AbstractBorder abstrakte Basisklasse für konkrete Border-Klassen
▻ EmptyBorder Klasse für "leere" Umrandungen Abstandsflächen
▻ LineBorder Klasse für Umrahmungen mit "normalen" Linien
▻ EtchedBorder Klasse für Umrahmungen mit eingeprägten bzw herausgearbeiteten Linien
▻ TitledBorder Klasse für mit einem Titel versehene Umrandungen
▻ CompoundBorder Klasse zur Zusammenfassung von zwei Umrandungen zu einer einzigen
◇ Es ist auch möglich eigene Border-Klassen zu definieren.
Diese sind zweckmässigerweise von der Klasse AbstractBorder abzuleiten.
Anwendungung von Umrandungen
◇ Prinzipiell können Umrandungen um jedes Objekt einer von JComponent abgeleiteten Klasse gesetzt werden.
◇ Jedoch arbeitet die LaF-Implementierung vieler Standard-Swing-Komponenten nicht sehr gut mit explizit gesetzten
Umrandungen.
Es wird daher empfohlen, Umrandungen grundsätzlich nur für JPanel- und JLabel-Komponenten zu verwenden.
Bei Komponenten dieser Klassen treten keine Probleme auf.
◇ Sollen andere Swing-Komponenten mit einer Umrandung versehen werden, so sollten diese zweckmässigerweise in
jeweils eine JPanel-Komponente eingebettet werden und um diese dann die Umrandung gesetzt werden.
Erzeugung von Border-Objekten
◇ Ein Border-Objekt kann von mehreren GUI-Komponenten-Objekten gemeinsam genutzt werden.
Daher ist es üblich und zweckmässig , Border-Objekte nicht mittels eines new-Ausdrucks zu erzeugen, sondern
hierfür statische Erzeugungs-Methoden der Klasse BorderFactory (Package javax.swing) einzusetzen
(Verwendung von Border-Objekten als Singletons).
22
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 554 – 02 – TH – 05
------------------------------------------------------------------------------------
Umrandungen für Swing-Komponenten in Java (2)
Die Klasse BorderFactory (Package javax.swing)
◇ Die Klasse BorderFactory stellt u.a. die folgenden statischen Erzeugungs-Methoden für Border-Objekte
bereit (Auswahl) :
public static Border createEmptyBorder(int top, int left, int bottom, int right)
Erzeugung eines EmptyBorder-Objekts mit den durch die Parameter festgelegten Größen (in Pixel)
public static Border createLineBorder(Color col, int thick)
Erzeugung eines LineBorder-Objekts, das die Farbe col und die Linien-Stärke thick (in Pixel) verwendet
public static Border createLineBorder(Color col)
Erzeugung eines LineBorder-Objekts, das die Farbe col und einen Defaultwert für die Linien-Stärke verwendet
public static Border createEtchedBorder()
Erzeugung eines EtchedBorder-Objekts für eingeprägte (etched-in) Umrandungen, das die aktuelle Hintergrundfarbe
des zu umrandenden Objekts für Hervorhebungen und Abschattungen verwendet
public static Border createEtchedBorder(int type)
Erzeugung eines EtchedBorder-Objekts für den durch type festgelegten Umrandungstyp, das die aktuelle Hinter-
grundfarbe des zu umrandenden Objekts für Hervorhebungen und Abschattungen verwendet
Zulässige Werte für type : EtchedBorder.RAISED herausgearbeitete Umrandung (etched-out)
EtchedBorder.LOWERED eingeprägte Umrandung (etched-in)
public static Border createEtchedBorder(int type, Color highlight, Color shadow)
Erzeugung eines EtchedBorder-Objekts für den durch type festgelegten Umrandungstyp, das die Farbe
highlight für Hervorhebungen und die Farbe shadow für Abschattungen verwendet
public static TitledBorder createTitledBorder(String str)
Erzeugung eines TitledBorder-Objekts, das die Beschriftung str und Defaultwerte für die übrigen Kenngrößen
verwendet.
Diese Defaultwerte sind : eingeprägte (?) Umrandung, Text auf oberem Rand, linksbündig, Font und Textfarbe durch die
Defaultwerte des aktuellen LaF bestimmt
public static TitledBorder createTitledBorder(Border bord, String str)
Erzeugung eines TitledBorder-Objekts aus dem existierenden Border-Objekt bord, das die Beschriftung
str sowie Defaultwerte für die Textposition (oberer Rand), die Textausrichtung (linksbündig) und Font und Textfarbe
(Defaultwerte des aktuellen LaF) verwendet.
public static TitledBorder createTitledBorder(Border bord, String str, int just,
int pos)
Erzeugung eines TitledBorder-Objekts aus dem existierenden Border-Objekt bord, das die Beschriftung
str sowie die Textposition pos, die Textausrichtung just und Defaultwerte für Font und Textfarbe (Defaultwerte
des aktuellen LaF) verwendet. Zulässige Werte für just und pos siehe Java-API-Doc
public static TitledBorder createTitledBorder(Border bord, String str, int just,
int pos, Font fnt, Color col)
Erzeugung eines TitledBorder-Objekts aus dem existierenden Border-Objekt bord, das die Beschriftung
str sowie die Textposition pos, die Textausrichtung just, den Font fnt und die Farbe col verwendet.
Zulässige Werte für just und pos siehe Java-API-Doc
public static CompoundBorder createCompoundBorder(Border out, Border in)
Erzeugung eines CompoundBorder-Objekts aus den existierenden Border-Objekten out (äussere Umrandung)
und in (innere Umrandung)
23
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 554 – 03 – TH – 02
------------------------------------------------------------------------------------
Umrandungen für Swing-Komponenten in Java (3)
Demonstrationsprogramm zu Umrandungen
// MultiBorderDemo.java
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class MultiBorderDemo extends JFrame
{ Container c;
JButton[] ba;
String titel;
public MultiBorderDemo(int sel)
{ c=getContentPane();
c.setLayout(new FlowLayout());
titel = "MultiBorderDemo";
JPanel[] pa = new JPanel[5];
for (int i=0; i<pa.length; i++)
{ pa[i] = new JPanel();
JButton but = new JButton("Button "+(i+1));
if(i==2)
{ but.setText(but.getText()+" with long title");
but.setFont(new Font("Serif", Font.ITALIC|Font.BOLD, 12));
but.setBackground(Color.ORANGE);
}
pa[i].add(but);
switch (sel)
{ case 1 :
pa[i].setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
break;
case 2 :
pa[i].setBorder(BorderFactory.createEtchedBorder());
break;
case 3 :
pa[i].setBorder(BorderFactory.createTitledBorder("button"));
break;
case 4 :
Border inbord = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
Border outbord = BorderFactory.createLineBorder(Color.GREEN, 5);
pa[i].setBorder(BorderFactory.createCompoundBorder(outbord, inbord));
break;
default :
break;
}
c.add(pa[i]);
}
setTitle(titel);
setSize(300, 240);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args)
{
if (args.length==1)
new MultiBorderDemo(Integer.parseInt(args[0])).setVisible(true);
else
new MultiBorderDemo(0).setVisible(true);
}
}
24
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 554 – 04 – TH – 01
-----------------------------------------------------------------------------------
Umrandungen für Swing-Komponenten in Java (4)
Beispiele für Umrandungen (vom Demonstrationsprogramm MultiBorderDemo erzeugte Fenster) keine Umrandung Umrandung mit EmptyBorder
Umrandung mit EtchedBorder Umrandung mit TitledBorder
Umrandung mit CompoundBorder aus Etchedborder und LineBorder
25
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 561 – 00 – TH – 06
------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (1)
Die Klasse JFrame (Package javax.swing)
◇ Wichtigste Swing-Top-Level-Container-Klasse
◇ Im Unterschied zur AWT-Top-Level-Container-Klasse Frame, von der JFrame abgeleitet ist, werden in einen
JFrame-Container die Komponenten nicht direkt eingefügt. Vielmehr besitzt jeder JFrame-Container, wie jeder
andere Swing-Top-Level-Container, einen speziellen Einfüge-Container, die sogenannte content pane.
Die content pane umfasst den gesamten "normalen" Einfüge-Bereich des Top-Level-Containers. In den Top-Level-
Container aufzunehmende Komponenten werden in seine content pane eingefügt.
Auch das Setzen eines Layout-Managers erfolgt in der content pane und nicht direkt im JFrame-Container. Anmerkung : Ab dem JDK 5.0 sind die Methoden add(), remove() und setLayoutManager() für die
Klasse JFrame so überschrieben, dass sie implizit die content pane verwenden. Sie können damit direkt für
JFrame-Container aufgerufen werden.
◇ Zusätzlich kann ein JFrame-Container über eine Menü-Leiste verfügen. Falls vorhanden, befindet sich diese ausser-
halb der content pane. Sie wird direkt in den Top-Level-Container eingefügt.
Weiterhin kann ein JFrame-Container eine Werkzeugleiste besitzen.
Diese wird analog zu anderen Komponenten in die content pane eingefügt.
◇ Als weiterer Unterschied zur AWT-Klasse Frame ist in der Klasse JFrame bereits – ohne explizite Registrierung
eines Window-Listeners – eine Reaktions-Funktionalität auf das Schliessen des Fensters implementiert.
Die genaue Reaktion kann mittels der Memberfunktion public void setDefaultCloseOperation(int op)
festgelegt werden.
Als gültige Werte für den Parameter op können die folgenden Konstanten verwendet werden :
- WindowConstants.DO_NOTHING_ON_CLOSE keine Reaktion
- WindowConstants.HIDE_ON_CLOSE das Fenster verstecken (unsichtbar machen), Default
- WindowConstants.DISPOSE_ON_CLOSE das Fenster verstecken und zerstören
- JFrame.EXIT_ON_CLOSE das Programm beenden (mittels System.exit(0))
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen (Auswahl) *) geerbt von Frame **) geerbt von Window
◇ Beispiel zum Einfügen von Komponenten JFrame frame = new JFrame();
Container c = frame.getContentPane();
c.setLayout(new FlowLayout()); // ab JDK 5.0 auch : frame.setLayout(...)
c.add(new JLabel("Hallo")); // ab JDK 5.0 auch : frame.add(...)
public JFrame() Erzeugung eines JFrame-Objekts ohne Titel, das durch das Objekt repräsen-
tierte Fenster ist unsichtbar
public JFrame(String title) Erzeugung eines JFrame-Objekts mit dem Titel title, das durch das
Objekt repräsentierte Fenster ist unsichtbar
public Container getContentPane() Ermitteln der content pane
public void setDefaultCloseOperation(int op) Setzen der Reaktion auf das Schliessen des Fensters
public void setJMenuBar(JMenuBar menu) Einfügen der Menuleiste menu
public void setTitle(String title) *) Setzen des Titels auf title
public void dispose() **) Zerstören des Fensters
public void pack() Anpassen der Fenstergröße so, dass alle darin enthaltenen Komponenten gerade Platz haben
**) (Berechnung des Platzbedarfs an Hand der bevorzugten Größe der Komponenten)
26
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 562 – 00 – TH – 07
------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (2)
Die Klasse JDialog (Package javax.swing)
◇ Diese Top-Level-Container-Klasse wird typischerweise dazu benutzt, temporär auf dem Bildschirm erscheinende
Fenster zu erzeugen, die für einen kurzen Dialog mit dem Benutzer vorgesehen sind ( Dialog-Fenster, Dialog-Box)
◇ Ein Dialog-Fenster ist üblicherweise an einen JFrame-Container oder ein anderes Dialog-Fenster gebunden
("Besitzer" des Dialog-Fensters). Es wird zusammen mit seinem "Besitzer" ikonifiziert/de-ikonifiziert oder geschlossen.
◇ Dialog-Fenster können modal gestaltet werden.
Das bedeutet, dass während der Sichtbarkeit eines Dialog-Fensters alle anderen Fenster des Programms (also auch
sein "besitzendes" Fenster) für Benutzereingaben gesperrt ist.
Die anderen Fenster können erst wieder verwendet werden, wenn der Dialog abgewickelt, d.h. das Dialog-Fenster wieder
geschlossen ist.
◇ Wie ein JFrame-Objekt besitzt auch ein JDialog-Objekt eine content pane.
In diese – und nicht direkt in das JDialog-Objekt – müssen aufzunehmende Komponenten eingefügt werden.
Auch ein eventueller Layout-Manager ist ebenfalls in der content pane zu setzen. Anmerkung : ab dem JDK 5.0 erfolgt dies implizit durch die für JDialog entsprechend überladenen Methoden
add() und setLayoutManager() (sowie das Entfernen durch remove())
◇ Ein JDialog-Objekt kann auch eine Menue-Leiste besitzen. Diese wird – wie bei JFrame-Objekten – direkt in
den Top-Level-Container und nicht in die content pane eingefügt.
◇ Konstruktoren (Auswahl)
Es existieren weitere Konstruktoren, mit denen statt eines Frame-(JFrame)-Objekts ein Dialog-(JDialog-)
Objekt als "Besitzer" festgelegt wird.
◇ Memberfunktionen (Auswahl) Die als Auswahl bei der Klasse JFrame angegebenen Memberfunktionen existieren auch für die Klasse JDialog : public Container getContentPane() public void setDefaultCloseOperation(int op) Der Wert EXIT_ON_CLOSE für op ist nicht zulässig public void setJMenuBar(JMenuBar menu) public setTitle(String title) *) geerbt von Dialog
public void dispose() **) geerbt von Window
public void pack() **) geerbt von Window Einige weitere Memberfunktionen (geerbt von Dialog) :
public JDialog() Erzeugung eines nicht-modalen JDialog-Objekts ohne Titel und ohne
explizit spezifizierten "Besitzer".
Ein verborgenes Frame-Objekt wird implizit als "Besitzer" gesetzt
public JDialog(Frame owner) Erzeugung eines nicht-modalen JDialog-Objekts ohne Titel und dem
Frame-(JFrame-)Objekt owner als "Besitzer"
public JDialog(Frame owner, Erzeugung eines nicht-modalen JDialog-Objekts mit dem Titel tit und
String tit) dem Frame-(JFrame-)Objekt owner als "Besitzer"
public JDialog(Frame owner, Erzeugung eines JDialog-Objekts ohne Titel und dem Frame-(JFrame-)
boolean mod) Objekt owner als "Besitzer". Der Parameter mod bestimmt die Modalität :
modal, wenn true, nicht-modal, wenn false
public JDialog(Frame owner, Erzeugung JDialog-Objekts mit dem Titel tit und dem Frame-
String tit, (JFrame-) Objekt owner als "Besitzer". Der Parameter mod bestimmt die
boolean mod) Modalität : modal, wenn true, nicht-modal, wenn false
public void setModal(boolean mod) Setzen der Modalität auf modal, wenn mod == true
public boolean isModal() Ermittlung der Modalität,
Rückgabewert : true, wenn modal, false andernfalls
27
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 563 – 01 – TH – 03
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (3-1)
Die Klasse JOptionPane (Package javax.swing)
◇ Diese Klasse ermöglicht auf relativ einfache Art und Weise die Erzeugung einfacher Standard-Dialog-Fenster.
◇ Die erzeugbaren Standard-Dialog-Fenster informieren den Programmbenutzer über irgendetwas und/oder fordern ihn zu
einer Eingabe auf.
◇ Die erzeugbaren Standard-Dialog-Fenster sind modal und können in der Größe nicht verändert werden.
◇ Als einfachste Möglichkeit zur Dialog-Fenster-Erzeugung stehen eine Reihe statischer Methoden zur Verfügung. Diese Methoden
▻ erzeugen ein weitgehend vorkonfiguriertes Dialog-Fenster, stellen es dar,
▻ warten auf eine zum Schliessen des Fensters führende Benutzeraktion (Schaltknopf-Betätigung, String-Eingabe)
▻ und liefern gegebenenfalls das Ergebnis der Benutzeraktion als Funktionswert zurück.
◇ Einige statische Klassen-Methoden als Beispiele :
Der bei allen Methoden vorhandene Parameter parent legt die Komponente fest, für die der Dialog jeweils aus-
geführt wird (null ist zulässig)
public static void showMessageDialog(Component parent, Object msg,
String title, int typeMsg)
Erzeugen eines Meldungs-Dialog-Fensters mit dem Titel title, das die Meldung msg (meist ein String) ausgibt und
ein durch den Meldungs-Typ typeMsg festgelegtes Default-Icon darstellt.
Zulässige Werte für den Meldungs-Typ typeMsg : JOptionPane.ERROR_MESSAGE
JOptionPane.INFORMATION_MESSAGE
JOptionPane.WARNING_MESSAGE
JOptionPane.QUESTION_MESSAGE
JOptionPane.PLAIN_MESSAGE (kein Icon)
public static void showMessageDialog(Component parent, Object msg)
Erzeugen eines Meldungs-Dialog-Fensters mit dem Titel "Message", das die Meldung msg (meist ein String) aus-
gibt und das Default-Icon für den Typ INFORMATION_MESSAGE darstellt
public static int showConfirmDialog(Component parent, Object msg,
String title, int typeOpt)
Erzeugen eines Bestätigungs-Dialog-Fensters mit dem Titel title, das die Meldung msg (meist ein String) ausgibt
und das Icon für QUESTION_MESSAGE sowie die durch den Options-Typ typeOpt festgelegten Options-Schalt-
knöpfe darstellt und auf die Auswahl eines Schaltknopfes wartet.
Zulässige Werte für den Options-Typ typeOpt : JOptionsPane.YES_NO_CANCEL_OPTION
JOptionsPane.YES_NO_OPTION
JOptionsPane.OK_CANCEL_OPTION
JOptionsPane.DEFAULT_OPTION (nur OK)
Der vom Benutzer ausgewählte Options-Schaltknopf bestimmt den zurückgegebenen Funktioswert (z.B. YES_OPTION)
public static int showConfirmDialog(Component parent, Object msg)
Erzeugen eines Bestätigungs-Dialog-Fensters mit einem Default-Titel, das die Meldung msg (meist ein String) ausgibt
und das Icon für QUESTION_MESSAGE sowie die Schaltknöpfe für den Options-Typ YES_NO_CANCEL_OPTION
darstellt und auf die Auswahl eines Schaltknopfes wartet.
Der vom Benutzer ausgewählte Options-Schaltknopf bestimmt den zurückgegebenen Funktioswert (z.B. YES_OPTION)
public static String showInputDialog(Component parent, Object msg)
Erzeugen eines Frage-Dialog-Fensters mit dem Titel "Input" (bzw "Eingabe"), das die Meldung msg (meist
ein String) ausgibt, das Icon für QUESTION_MESSAGE darstellt und auf die Eingabe eines Strings wartet.
Der vom Benutzer eingegebene String wird als Funktionswert zurückgegeben.
28
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 563 – 02 – TH – 01
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (3-2)
Beispiele für von JOptionPane erzeugte Standard-Dialog-Fenster
// Meldungs-Dialog : Fehler-Meldung
JOptionPane.showMessageDialog(this,
"Lesefehler !",
"Eine Fehler-Meldung",
JOptionPane.ERROR_MESSAGE);
// Meldungs-Dialog : Information
JOptionPane.showMessageDialog(this,
"Die Festplatte ist zerstoert!",
"Eine Information",
JOptionPane.INFORMATION_MESSAGE);
// Meldungs-Dialog : Warnung
JOptionPane.showMessageDialog(this,
"Hoeren Sie auf !",
"Eine Warnung",
JOptionPane.WARNING_MESSAGE);
// Meldungs-Dialog : Frage
JOptionPane.showMessageDialog(this,
"Wollen Sie das wirklich ?",
"Eine Frage",
JOptionPane.QUESTION_MESSAGE);
// Bestätigungs-Dialog
// Default-Titel und
// Default-Options-Typ
int opt;
opt = JOptionPane.showConfirmDialog(this,
"Was wollen Sie ?");
// Frage-Dialog
// Default-Titel
String name;
name = JOptionPane.showInputDialog(this,
"Ihr Name ? ");
29
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 564 – 00 – TH – 02
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (4)
Die Klasse JLabel (Package javax.swing)
◇ Diese Klasse dient zur Erzeugung von Beschriftungs-Objekten.
◇ Im Unterschied zu den AWT-Label-Objekten können JLabel-Objekte nicht nur Text, sondern auch Bilder dar-
stellen (auch beides kombiniert)
◇ Die Ausrichtung sowohl des Textes als auch des Bildes innerhalb des Darstellungsbereichs eines JLabel-Objekts
kann festgelegt werden.
Default-Ausrichtung für Text : horizontal linksbündig, vertikal zentriert
Default-Ausrichtung für Bilder : horizontal und vertikal zentriert Explizite Festlegung der Ausrichtung : SwingConstants.CENTER (zentriert)
SwingConstants.RIGHT (rechtsbündig)
SwingConstants.LEFT (linksbündig)
SwingConstants.TOP (obenbündig)
SwingConstants.BOTTOM (untenbündig)
◇ JLabel-Objekte können nicht auf vom Benutzer ausgelöste Ereignisse (Eingaben) reagieren.
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen (Auswahl)
◇ Anmerkungen zu darzustellenden Bildern
▻ Bilder werden als Instanzen des Interfaces Icon (Package javax.swing) referiert.
Im Regelfall handelt es sich bei Ihnen um Objekte der dieses Interface implementierenden Klasse ImageIcon
▻ Objekte der Klasse ImageIcon (Package javax.swing) können aus einer Bild-Datei erzeugt werden mit dem
Konstruktor : public ImageIcon(String dateipfad) Der Parameter dateipfad spezifiziert die Bild-Datei.
public JLabel(String text) Erzeugung eines JLabel-Objekts mit dem Text text,
der Text ist horizontal linksbündig ausgerichtet
public JLabel(String text, int halign) Erzeugung eines JLabel-Objekts mit dem Text text,
der Text ist horizontal gemäß halign ausgerichtet
public JLabel(Icon image) Erzeugung eines JLabel-Objekts mit dem Bild image,
das Bild ist horizontal zentriert ausgerichtet
public JLabel(Icon image, int halign) Erzeugung eines JLabel-Objekts mit dem Bild image,
das Bild ist horizontal gemäß halign ausgerichtet
public String getText() Rückgabe des dargestellten Textes
public Icon getIcon() Rückgabe des dargestellten Bildes
public void setText(String text) Setzen des darzustellenden Textes auf text
public void setIcon(Icon image) Setzen des darzustellenden Bildes auf image
public void setHorizontalAlignment(int halign) Setzen der horizontalen Ausrichtung
gemäß halign (für Text und Bild)
public void setVerticalAlignment(int valign) Setzen der vertikalen Ausrichtung
gemäß valign (für Text und Bild)
30
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 565 – 00 – TH – 03
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (5)
Die Klasse JButton (Package javax.swing)
◇ Diese Klasse dient zur Erzeugung von einfachen Schaltknöpfen (Schaltflächen).
◇ Auch JButton-Objekte können – im Unterschied zu den AWT-Button-Objekten – sowohl Text als auch ein Bild
(auch beides kombiniert) darstellen.
◇ Auch bei JButton-Objekten kann die Ausrichtung sowohl des Textes als auch des Bildes innerhalb ihres Darstel-
lungsbereichs festgelegt werden.
Default-Ausrichtung für Text und Bilder : horizontal rechtsbündig, vertikal zentriert Explizite Festlegung der Ausrichtung : SwingConstants.CENTER (zentriert)
SwingConstants.RIGHT (rechtsbündig)
SwingConstants.LEFT (linksbündig)
SwingConstants.TOP (obenbündig)
SwingConstants.BOTTOM (untenbündig)
◇ Im Unterschied zu JLabel-Objekten können JButton-Objekte (Schaltknöpfe !) vom Benutzer veranlasste Ereig-
nisse auslösen. Ein Schaltknopf kann auch den Focus besitzen und dann auch Tastatur-Eingaben empfangen.
Ein Schaltknopf kann vom Benutzer – z.B. durch einen Mausklick oder bei vorhandenen Focus durch die Leertaste –
betätigt ("gedrückt") werden. Ein "gedrückter" Schaltknopf ändert seine Hintergrundfarbe.
◇ Konstruktoren (Auswahl)
◇ Der überwiegende Teil der von der Klasse JButton angebotenen Schnittstelle ist geerbt von der Klasse AbstractButton.
Teilweise werden die gleichen Memberfunktionen – mit gleicher Funktionalität – wie bei der Klasse JLabel
zur Verfügung gestellt
Memberfunktionen (von AbstractButton geerbt, Auswahl)
public JButton() Erzeugung eines JButton-Objekts ohne "Inhalt"
public JButton(String text) Erzeugung eines JButton-Objekts das mit dem Text
text beschriftet ist (horizontal rechtsbündig ausgerichtet)
public JButton(Icon image) Erzeugung eines JButton-Objekts, das mit dem Bild
image versehen ist (horizontal rechtsbündig ausgerichtet)
public JButton(String text, Icon image) Erzeugung eines JButton-Objektsd, das mit dem Text
text beschriftet und mit dem Bild image versehen ist
public String getText() Rückgabe des dargestellten Textes
public Icon getIcon() Rückgabe des dargestellten Bildes
public void setText(String text) Setzen des darzustellenden Textes auf text
public void setIcon(Icon image) Setzen des darzustellenden Bildes auf image
public void setHorizontalAlignment(int halign) Setzen der horizontalen Ausrichtung
gemäß halign (für Text und Bild)
public void setVerticalAlignment(int valign) Setzen der vertikalen Ausrichtung
gemäß valign (für Text und Bild)
31
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 566 – 00 – TH – 05
------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (6)
Die Klasse JTextField (Package javax.swing)
◇ Diese Klasse ist von der abstrakten Basisklasse JTextComponent (Package javax.swing.text) abgeleitet.
Sie dient zur Erzeugung von editierbaren einzeiligen Textfeldern.
Die Editierbarkeit kann ein- und ausgeschaltet werden (Default nach Objekt-Erzeugung : eingeschaltet).
◇ JTextField-Objekte können sowohl zur Ausgabe als auch zur Eingabe (wenn die Editierbarkeit eingeschaltet ist)
von Text verwendet werden.
◇ Die Größe eines Textfeldes (= Anzahl der dargestellten Zeichenpositionen) kann kleiner (und natürlich auch größer)
als die Textlänge sein. Das heisst, dass auch Text eingegeben werden kann, desen Länge die Anzahl der darstellbaren
Positionen überschreitet.
◇ Die horizontale Ausrichtung des Textes innerhalb des dargestellten Zeilenfensters kann festgelegt werden.
Hierfür stehen die folgenden Konstanten zur Verfügung :
- JTextField.LEFT (linksbündig)
- JTextField.RIGHT (rechtsbündig)
- JTextField.CENTER (zentriert)
- JTextField.LEADING (Darstellung der führenden Zeichen, wenn Feldlänge kleiner als Textlänge, default)
- JTextField.TRAILING (Darstellung der Zeichen am Ende, wenn Feldlänge kleiner als Textlänge)
◇ Die Editierfunktionalität umfasst auch die Zusammenarbeit mit dem Clipboard : Text kann aus dem Clipboard einge-
fügt bzw im Textfeld markiert und – ausgeschnitten oder kopiert – in das Clipboard eingefügt werden.
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen (Auswahl) Die meisten der nachfolgend aufgeführten Memberfunktionen sind von der Klasse JTextComponent geerbt.
*) geerbt von JTextComponent (Package javax.swing.text)
public JTextField() Erzeugung eines "leeren" JTextField-Objekts, die Feldgröße = 0
public JTextField(String text) Erzeugung eines JTextField-Objekts, das mit text initialisiert ist,
die Feldgröße wird durch die Länge von text bestimmt.
public JTextField(int cols) Erzeugung eines "leeren" JTextField-Objekts,
die Feldgröße ist durch cols festgelegt.
public JTextField(String text, Erzeugung eines JTextField-Objekts, das mit text initialisiert ist,
int cols) die Feldgröße ist durch cols festgelegt
public void setColumns(int cols) Setzen der Feldgröße auf cols, das Layout wird ungültig gesetzt
public String getText() *) Rückgabe des im Textfeld enthaltenen Textes
public String getSelectedText() *) Rückgabe des markierten Teils des im Textfeld enthaltenen Textes
public void setText(String text) *) Setzen des im Textfeld enthaltenen Textes auf text
public void setEditable(boolean b) Setzen / Aufheben der Editierbarkeit des Textfeldes gemäß b
*) b==true : Setzen der Editierbarkeit, andernfalls Aufheben
public boolean isEditable() *) Ermittelung der Editierbarkeit des Textfeldes
Rückgabewert ==true : editierbar, andernfalls nicht editierbar
public void setHorizontalAlignment(int halign) Setzen der horizontalen Ausrichtung des
Textfeldes auf halign
32
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 567 – 01 – TH – 02
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (7-1)
Die Klasse JTextArea (Package javax.swing)
◇ Diese Klasse ist ebenfalls von der Klasse JTextComponent abgeleitet.
Sie dient zur Darstellung editierbarer mehrzeiliger Textfelder.
Wie bei der Klasse JTextField kann die Editierbarkeit ein- und ausgeschaltet werden (Default nach Objekt-
Erzeugung : eingeschaltet).
◇ JTextArea-Objekte können sowohl zur Ausgabe als auch zur Eingabe (bei eingeschalteter Editierbarkeit) von Text,
der mehrere Zeilen umfassen kann, eingesetzt werden.
Die Größe des im JTextArea-Objektes darzustellenden Textes kann sich damit dynamisch ändern.
◇ Auch bei dieser Klasse schliesst die Editierfunktionalität die Verwendung des Clipboards ein : Text kann aus dem Clip-
board eingefügt bzw im Textfeld markiert und – ausgeschnitten oder kopiert – in das Clipboard eingefügt werden.
◇ Die Klasse JTextArea stellt mehrere Methoden zur Verfügung, mit denen der dargestellte Text auch vom Programm
aus editiert werden kann.
U.a. existieren Methoden zum zeilenweisen Text-Zugriff sowie zum Einfügen und Anhängen von Text.
◇ Die Größe des im JTextArea-Objektes darzustellenden Textes kann sich infolge des benutzer-initiierten oder pro-
gramm-initiierten Editierens dynamisch ändern.
◇ Es ist möglich, für ein JTextArea-Objekt die Anzahl der Zeilen und Spalten festzulegen. Diese dienen zur Ermitt-
lung seiner bevorzugten Größe (preferred size), die aber nicht der Größe des tatsächlich dargestellten Textfensters
(Darstellungsbereich) entsprechen muß. Diese wird vielmehr durch den eingesetzten Layout-Manager gegebenenfalls
unter Berücksichtigung der Größe des umfassenden Containers festgelegt.
◇ Für den Fall, dass eine darzustellende Zeile länger als die dargestellte Textfenster-Breite ist, kann ein automatischer
Zeilenumbruch eingeschaltet werden
Bei eingeschalteten Zeilenumbruch kann festgelegt werden, ob ein Umbruch nach jedem Zeichen (zeichenweiser Um-
bruch) oder nur an einer Wortgrenze (wortweiser Umbruch) erfolgen kann.
Defaultmässig ist der Zeilenumbruch ausgeschaltet. Der nicht in das dargestellte Fenster passende Zeilenteil ist dann
nicht sichtbar.
Analoges gilt, wenn die tatsächliche Anzahl der darzustellenden Textzeilen größer als die durch das dargestellte Text-
fenster gegebene Zeilenzahl ist.
◇ JTextArea-Objekte besitzen keine Scroll-Fähigkeiten (Unterschied zu der AWT-Klasse TextArea).
Diese lassen sich aber durch das Einbetten eines JTextArea-Objektes in ein JScrollPane-Objekt realisieren.
In diesem Fall wird für den Scrollbereich die durch Zeilen- und Spaltenzahl festgelegte bevorzugte Größe berücksichtigt.
◇ Konstruktoren (Auswahl)
public JTextArea() Erzeugung eines "leeren" JTextArea-Objekts (Die Referenz auf den
enthaltenen String ist null)
Die Werte für die Anzahl der Zeilen und Spalten werden auf 0 gesetzt
public JTextArea(String text) Erzeugung eines JTextArea-Objekts, das mit text initialisiert ist,
Die Werte für die Anzahl der Zeilen und Spalten werden auf 0 gesetzt
public JTextArea(int rows, Erzeugung eines "leeren" JTextArea-Objekts,
int cols) Die Anzahl der Zeilen ist durch rows, die Anzahl der Spalten durch
cols festgelegt.
public JTextArea(String text, Erzeugung eines JTextArea-Objekts, das mit text initialisiert ist,
int rows, Die Anzahl der Zeilen ist durch rows, die Anzahl der Spalten durch
int cols) cols festgelegt.
33
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 567 – 02 – TH – 02
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (7-2)
Die Klasse JTextArea (Package javax.swing), Forts.
◇ Memberfunktionen (Auswahl) Wie in der Klasse JTextField werden zahlreiche Memberfunktionen von der Klasse JTextComponent geerbt.
Zusätzlich definiert die Klasse JTextArea eine Reihe eigener Methoden
*) geerbt von JTextComponent (Package javax.swing.text)
public String getText() *) Rückgabe des im Textfeld enthaltenen Textes
public String getSelectedText() *) Rückgabe des markierten Teils des im Textfeld enthaltenen Textes
public void setText(String text) *) Setzen des im Textfeld enthaltenen Textes auf text
public void setEditable(boolean b) Setzen / Aufheben der Editierbarkeit des Textfeldes gemäß b
*) b==true : Setzen der Editierbarkeit, andernfalls Aufheben
public boolean isEditable() *) Ermittlung der Editierbarkeit des Textfeldes
Rückgabewert ==true : editierbar, andernfalls nicht editierbar
public void setRows(int rows) Setzen der Anzahl Zeilen auf rows
public void setColumns(int cols) Setzen der Anzahl Spalten auf cols
public int getRows() Ermittlung der festgelegten Zeilen-Anzahl
public int getColumns() Ermittlung der festgelegten Spalten-Anzahl
public int getLineCount() Ermittlung der tatsächlich im Text vorhandenen Zeilenzahl
public void setLineWrap(boolean b) Setzen/Aufheben des automatischen Zeilenumbruchs gemäß b
b==true : Setzen des Zeilenumbruchs, andernfalls Aufheben
public boolean getLineWrap() Ermittlung, ob automatischer Zeilenumbruch gesetzt ist
Rückgabewert ==true : Zeilenumbruch ist gesetzt
public void setWrapStyleWord(boolean b) Setzen der Art des Zeilenumbruchs gemäß b
b==true : wortweiser Zeilenumbruch
b==false : zeichenweiser Zeilenumbruch (Default)
public boolean getWrapStyleWord() Ermittlung der Art des Zeilenumbruchs
Rückgabewert ==true : wortweiser Zeilenumbruch
Rückgabewert ==false : zeichenweiser Zeilenumbruch
void append(String str) Anhängen des Strings str an das Ende des dargestellten Textes
void insert(String str, int pos) Einfügen des Strings str an der Position pos im Text
void replaceRange(String str, Ersetzen des Textes zwischen den Positionen beg und end
int beg, int end) durch den String str
34
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 567 – 03 – TH – 01
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (7-3)
Demonstrationsprogramm zur Klasse JTextArea (JTextAreaDemo)
// JTextAreaDemo.java
import java.awt.*;
import javax.swing.*;
import java.io.*;
public class JTextAreaDemo extends JFrame
{
private final static String DEF_FILE_NAME = "schlechterwitz.txt";
private Container c;
private JTextField tf;
private JTextArea ta;
public JTextAreaDemo(String dname)
{ super("JTextAreaDemo");
tf = new JTextField("Inhalt der Datei \"" + dname + '\"');
tf.setHorizontalAlignment(JTextField.CENTER);
tf.setFont(new Font("SansSerif", Font.BOLD, 14));
tf.setBackground(Color.YELLOW);
c=getContentPane();
ta = new JTextArea(20, 50);
if (dname!=null)
fillTextAreaFromFile(dname);
ta.setFont(new Font("SansSerif", Font.PLAIN, 13));
//ta.setLineWrap(true); // Setzen des automatischen Zeilenumbruchs
//ta.setWrapStyleWord(true); // Setzen der Umbruchsart auf wortweise
c.add(tf, BorderLayout.NORTH);
c.add(ta);
setSize(360, 270);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void fillTextAreaFromFile(String dname)
{ try
{ BufferedReader bfr = new BufferedReader(new FileReader(dname));
String line;
while ((line=bfr.readLine()) != null)
ta.append(line + '\n');
bfr.close();
}
catch(IOException ex)
{ System.out.println("Exception " + ex.getMessage());
}
}
public static void main(String[] args)
{ String fname;
if (args.length==0)
fname = DEF_FILE_NAME;
else
fname = args[0];
new JTextAreaDemo(fname).setVisible(true);
}
}
35
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 567 – 04 – TH – 01
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (7-4)
Ausgabe des Demonstrationsprogramms zur Klasse JTextArea (JTextAreaDemo)
◇ Automatischer Zeilenumbruch nicht gesetzt (default)
◇ Automatischer Zeilenumbruch gesetzt (zeichenweiser Umbruch)
◇ Automatischer Zeilenumbruch gesetzt (wortweiser Umbruch)
36
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 568 – 01 – TH – 03
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (8-1)
Die Klasse JScrollPane (Package javax.swing)
◇ Objekte dieser Klasse dienen zur Einbettung anderer GUI-Komponenten in einen scrollbaren Darstellungsbereich.
Statt die GUI-Komponente direkt in einen Container einzufügen, wird sie in ein JScrollPane-Objekt eingebettet
und dieses dann in den Container eingefügt.
◇ JScrollPane-Objekte verwalten einen Darstellungsbereich (viewport), in dem die eingebettete GUI-Komponente
eingeblendet wird. Wenn die eingebettete Komponente größer als der zur Verfügung stehende Darstellungsbereich ist, wird sie nur aus-
schnittsweise angezeigt. Mit Hilfe von zwei Schiebereglern (scroll bars, horizontale und vertikale Bildlaufleiste) kann
der dargestellte Ausschnitt dynamisch verändert werden.
◇ Es kann festgelegt werden, wann die Bildlaufleisten sichtbar sein sollen (Scroll Bar Policy) :
▻ nur sichtbar, wenn nötig (default)
▻ immer sichtbar
▻ nie sichtbar Dies kann – getrennt für die vertikale und horizontale Bildlaufleiste – im Konstruktor bei der JScrollPane-Objekt-
Erzeugung oder später mittels spezieller Memberfunktionen erfolgen. Zur Festlegung stehen die folgenden – im implementierten Interface ScrollPaneConstants (Package
javax.swing) definierten – Konstanten zur Verfügung :
- JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED (vertikale Bildlaufleiste nur bei Bedarf sichtbar)
- JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED (horizontale Bildlaufleiste nur bei Bedarf sichtbar)
- JScrollPane.VERTICAL_SCROLLBAR_ALWAYS (vertikale Bildlaufleiste immer sichtbar)
- JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS (horizontale Bildlaufleiste immer sichtbar)
- JScrollPane.VERTICAL_SCROLLBAR_NEVER (vertikale Bildlaufleiste nie sichtbar)
- JScrollPane.HORIZONTAL_SCROLLBAR_NEVER (horizontale Bildlaufleiste nie sichtbar)
◇ Prinzipiell kann jede beliebige GUI-Komponente in ein JScrollPane-Objekt eingebettet werden.
Diese kann im Konstruktor angegeben oder mittels einer entsprechenden Memberfunktion festgelegt werden.
◇ Für ein JScrollPane-Objekt können zusätzlich ein Zeilen-Header, ein Spalten-Header und Eck-Komponenten
festgelegt werden.
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen (Auswahl)
public JScrollPane() Erzeugung eines "leeren" JScrollPane-Objekts.
Beide Bildlaufleisten werden nur bei Bedarf dargestellt
public JScrollPane(Component view) Erzeugung eines JScrollPane-Objekts, in dem das GUI-
Komponenten-Objekt view eingebettet ist.
Beide Bildlaufleisten werden nur bei Bedarf dargestellt
public JScrollPane(Component view, Erzeugung eines JScrollPane-Objekts, in dem das GUI-
int vsbPol, int hsbPol) Komponenten-Objekt view eingebettet ist
Die Sichtbarkeit der Bildlaufleisten wird durch vsbPol (verti-
kal und hsbPol (horizontal) festgelegt
public void setVerticalScrollBarPolicy(int pol) Setzen der ScrollBarPolicy für die vertikale
Bildlaufleiste auf pol
public void setHorizontalScrollBarPolicy(int pol) Setzen der ScrollBarPolicy für die horizontale
Bildlaufleiste auf pol
public void setViewportView(Component view) Einbettung des GUI-Komponenten-Objekts view
37
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 568 – 02 – TH – 01
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (8-2)
Demonstrationsprogramm zur Klasse JScrollPane (JScrollPaneDemo)
// JScrollPaneDemo.java
// Einbettung eines JTextArea-Objekts in ein JScrollPane-Objekt
// Modifikation des Demonstrations-Programms zur Klasse JTextArea
import java.awt.*;
import javax.swing.*;
import java.io.*;
public class JScrollPaneDemo extends JFrame
{
final static String DEF_FILE_NAME = /*"beispiel.txt"*/"schlechterwitz.txt";
private Container c;
private JTextField tf;
private JTextArea ta;
private JScrollPane sp;
public JScrollPaneDemo(String dname)
{ super("JScrollPaneDemo");
tf = new JTextField("Inhalt der Datei \"" + dname + '\"');
tf.setHorizontalAlignment(JTextField.CENTER);
tf.setFont(new Font("SansSerif", Font.BOLD, 14));
tf.setBackground(Color.YELLOW);
c=getContentPane();
ta = new JTextArea(20,50);
if (dname!=null)
fillTextAreaFromFile(dname);
ta.setFont(new Font("SansSerif", Font.PLAIN, 13));
sp = new JScrollPane(ta);
c.add(tf, BorderLayout.NORTH);
c.add(sp);
setSize(380, 250);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void fillTextAreaFromFile(String dname)
{ try
{ BufferedReader bfr = new BufferedReader(new FileReader(dname));
String line;
while ((line=bfr.readLine()) != null)
ta.append(line + '\n');
bfr.close();
}
catch(IOException ex)
{ System.out.println("Exception " + ex.getMessage());
}
}
public static void main(String[] args)
{
String fname;
if (args.length==0)
fname = DEF_FILE_NAME;
else
fname = args[0];
new JScrollPaneDemo(fname).setVisible(true);
}
}
38
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 568 – 03 – TH – 01
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (8-3)
Ausgabe des Demonstrationsprogramms zur Klasse JScrollPane (JScrollPaneDemo)
◇ Automatischer Zeilenumbruch für das eingebettete JTextArea-Objekt nicht gesetzt (default)
◇ Automatischer Zeilenumbruch für das eingebettete JTextArea-Objekt gesetzt (wortweiser Umbruch)
◇ Automatischer Zeilenumbruch für das eingebettete JTextArea-Objekt nicht gesetzt (default)
39
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 568 – 04 – TH – 02
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (8-4)
Weiteres Demonstrationsprogramm zur Klasse JScrollPane (JScrollPaneDemo2)
// JScrollPaneDemo2.java
// Einbettung eines JButton-Objekts mit einem Bild in ein JScrollPane-Objekt
import java.awt.*;
import javax.swing.*;
import java.io.*;
public class JScrollPaneDemo2 extends JFrame
{
final static String DEF_FILE_NAME = "UnixCountry.jpg";
private Container c;
private JButton but; // alternativ : JLabel but;
private JTextField tf;
private JScrollPane sp;
public JScrollPaneDemo2(String dname)
{ super("JScrollPaneDemo2");
tf = new JTextField("Inhalt der Datei \"" + dname + '\"');
tf.setHorizontalAlignment(JTextField.CENTER);
tf.setFont(new Font("SansSerif", Font.BOLD, 14));
tf.setBackground(Color.YELLOW);
c=getContentPane();
Icon pict = new ImageIcon(dname);
but = new JButton(pict); // alternativ : but = new JLabel(pict);
sp = new JScrollPane(but);
c.add(tf, BorderLayout.NORTH);
c.add(sp);
setSize(550, 350);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args)
{ String fname;
if (args.length==0)
fname = DEF_FILE_NAME;
else
fname = args[0];
new JScrollPaneDemo2(fname).setVisible(true);
}
}
40
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 568 – 05 – TH – 01
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (8-5)
Ausgabe des weiteren Demonstrationsprogramms zur Klasse JScrollPane (JScrollPaneDemo2)
◇ verschiedene Stellungen der Schieberegler (Bildlaufleiste)
41
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 569 – 00 – TH – 02
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (9)
Die Klasse JCheckBox (Package javax.swing)
◇ Diese Klasse dient zur Erzeugung von Auswahlfeldern.
Ein Auswahlfeld (check box) ist ein kleines Kästchen, das bei der Anwahl selektiert und deselektiert werden kann.
Der jeweilige Selektionszustand wird angezeigt :
De-selektiert ist das Kästchen leer, selektiert enthält es einen kleinen Haken.
◇ Ein JCheckBox-Objekt dient i.a. zur Darstellung eines logischen Wertes (boolean) auf einer GUI-Oberfläche.
◇ In einer Gruppe von JCheckBox-Objekten (Auswahlfeldern) können beliebig viele selektiert sein
◇ Ein JCheckBox-Objekt kann mit einem Text beschriftet oder/und mit einem Bild versehen werden.
Ein Bild ersetzt dabei das Auswahlfeld-Kästchen in der Darstellung. Eine eventuelle Selektion kann dann optisch nicht
mehr erkannt werden.
◇ Die Klasse ist von der Klasse JToggleButton abgeleitet, die ihrerseits die abstrakte Klasse AbstractButton
als direkte Basisklasse hat.
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen : Ein großer Teil der angebotenen Schnittstelle ist von der Klasse AbstractButton geerbt,
u.a. :
public JCheckBox() Erzeugung eines nicht selektierten JCheckBox-Objekts
ohne Text und ohne Bild
public JCheckBox(String text) Erzeugung eines nicht selektierten JCheckBox-Objekts,
mit dem Text text beschriftet
public JCheckBox(String text, Erzeugung eines JCheckBox-Objekts, dessen Anfangs-
boolean select) Selektionszustand durch select festgelegt ist
(select==true : selektiert), Beschriftung mit Text text
public JCheckBox(Icon image) Erzeugung eines nicht selektierten JCheckBox-Objekts,
mit dem Bild image versehen
public JCheckBox(Icon image, Erzeugung eines JCheckBox-Objekts, dessen Anfangs-
boolean select) Selektionszustand durch select festgelegt ist
(select==true : selektiert), mit dem Bild image versehen
public JCheckBox(String text, Erzeugung eines nicht selektierten JCheckBox-Objekts,
Icon image) mit dem Text text beschriftet und dem Bild image versehen
public JCheckBox(String text, Erzeugung eines JCheckBox-Objekts, dessen Anfangs-
Icon image, Selektionszustand durch select festgelegt ist
boolean select) (select==true : selektiert), mit dem Text text beschriftet
und mit dem Bild image versehen
public void setSelected(boolean b) Setzen des Selektionszustands gemäß b
b==true : selektiert, andernfalls nicht selektiert
public boolean isSelected() Ermittlung des Selektionszustands
Rückgabewert ==true : selektiert,
==false : nicht selektiert
42
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 56A – 01 – TH – 04
------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (10-1)
Die Klasse JRadioButton (Package javax.swing)
◇ Diese Klasse dient ebenfalls zur Erzeugung von Auswahlfeldern.
JRadioButton-Objekte können somit auch zur Darstellung logischer Werte (boolean) auf einer GUI-Oberfläche
eingesetzt werden.
◇ Im Unterschied zur Klasse JCheckBox werden aber mehrere JRadioButton-Objekte meist so zu einer Gruppe
zusammengefasst, dass immer nur ein Auswahlfeld aus der Gruppe selektiert werden soll (und kann) (Gruppe alter-
nativer Auswahlfelder).
◇ Ein Auswahlfeld der Klasse JRadioButton wird durch einen kleinen Kreis dargestellt. Im unselektierten Zustand
ist der Kreis leer, bei Selektion erscheint ein Punkt im Kreis.
◇ Die Klasse JRadioButton ist ebenfalls von der Klasse JToggleButton und damit auch von der abstrakten
Klasse AbstractButton abgeleitet.
◇ Auch ein JRadioButton-Objekt kann mit einem Text beschriftet oder/und mit einem Bild versehen werden.
Ein Bild ersetzt dabei den Auswahlfeld-Kreis in der Darstellung. Eine eventuelle Selektion kann dann optisch nicht
mehr erkannt werden.
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen : Die angebotene Schnittstelle entspricht weitgehend – soweit sie von der Klasse AbstractButton geerbt ist –
der Schnittstelle der Klasse JCheckBox.
U.a. stehen somit auch die folgenden Methoden zur Verfügung :
public JRadioButton() Erzeugung eines nicht selektierten JRadioButton-Objekts
ohne Text und ohne Bild
public JRadioButton (String text) Erzeugung eines nicht selektierten JRadioButton -Objekts,
mit dem Text text beschriftet
public JRadioButton (String text, Erzeugung eines JRadioButton -Objekts, dessen Anfangs-
boolean select) Selektionszustand durch select festgelegt ist
(select==true : selektiert), Beschriftung mit Text text
public JRadioButton (Icon image) Erzeugung eines nicht selektierten JRadioButton -Objekts,
mit dem Bild image versehen
public JRadioButton (Icon image, Erzeugung eines JRadioButton -Objekts, dessen Anfangs-
boolean select) Selektionszustand durch select festgelegt ist
(select==true : selektiert), mit dem Bild image versehen
public JRadioButton (String text, Erzeugung eines nicht selektierten JRadioButton -Objekts,
Icon image) mit dem Text text beschriftet und dem Bild image versehen
public JRadioButton (String text, Erzeugung eines JRadioButton -Objekts, dessen Anfangs-
Icon image, Selektionszustand durch select festgelegt ist
boolean select) (select==true : selektiert), mit dem Text text beschriftet
und mit dem Bild image versehen
public void setSelected(boolean b) Setzen des Selektionszustands gemäß b
b==true : selektiert, andernfalls nicht selektiert
public boolean isSelected() Ermittlung des Selektionszustands
Rückgabewert ==true : selektiert,
==false : nicht selektiert
43
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 56A – 02 – TH – 03
------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (10-2)
Die Klasse ButtonGroup (Package javax.swing)
◇ Objekte dieser Klasse dienen zur logischen Zusammenfassung mehrerer JRadioButton-Objekte zu einer Gruppe,
in der immer nur ein Objekt selektiert werden kann.
◇ Sie stellen selbst keine GUI-Komponenten dar und erscheinen deshalb auch nicht auf der GUI-Oberfläche.
◇ Nach der Erzeugung eines ButtonGroup-Objekts und dem Hinzufügen der JRadioButton-Objekte, die zusam-
mengefasst werden sollen, sind alle JRadioButton-Objekte zunächst de-selektiert.
Nach der erstmaligen Selektion eines JRadioButton-Objekts ist immer genau ein Objekt der Gruppe selektiert.
Es gibt danach keine Möglichkeit mehr, alle Objekte gleichzeitig in den de-selektierten Zustand zu versetzen.
◇ Konstruktor :
◇ Memberfunktionen :
◇ Anmerkung :
▻ Genaugenommen können durch ein ButtonGroup-Objekt nicht nur JRadioButton-Objekte sondern Objekte
jeder von AbstractButton abgeleiteten Klasse zusammengefasst werden (Parameter von add() !!!).
Allerdings ist eine derartige Zusammenfassung nicht immer sinnvoll.
▻ Beispielsweise lassen sich auch JCheckBox-Objekte derartig zu einer Gruppe zusammenfassen. Diese Gruppe
ver hält sich dann wie eine JRadioButton-Gruppe (nur eine Checkbox kann jeweils alternativ selektiert werden),
was aber der typischen Anwendung von JCheckBox-Objekten wiederspricht.
▻ Bei Objekten einiger von AbstractButton abgeleiteten Klassen (z.B. JButton und JMenuItem) macht
die Zusammenfassung zu einer Gruppe schon deshalb keinen Sinn, weil sie den jeweiligen Selektionszustand nicht
anzeigen.
public ButtonGroup() Erzeugung eine neuen ButtonGroup-Objekts
public void add(AbstractButton b) Hinzufügen des Buttons (konkret JRadioButton-Objekts) b
zur Gruppe
public void remove(AbstractButton b) Entfernen des Buttons (konkret JRadioButton-Objekts) b
aus der Gruppe
public int getButtonCount() Rückgabe der Anzahl in der Gruppe enthaltenen
AbstractButton-(konkret JRadioButton-)Objekte
public Enumeration<AbstractButton> Rückgabe aller in der Gruppe enthaltenen AbstractButton-
getElements() (konkret JRadioButton-)Objekte
44
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 56A – 03 – TH – 01
-----------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (10-3)
Demonstrationsprogramm zu den Klassen JCheckBox und JRadioButton
// AuswahlfeldDemo.java
import java.awt.*;
import javax.swing.*;
public class AuswahlfeldDemo extends JFrame
{
private Container c;
private JCheckBox[] cba;
private JRadioButton[] rba;
public AuswahlfeldDemo(int anz)
{
setTitle("AuswahlfeldDemo");
c = getContentPane();
c.setLayout(new GridLayout(2,0));
cba = new JCheckBox[anz];
for (int i=0; i<cba.length; i++)
{
cba[i] = new JCheckBox("Auswahl " + (i+1));
c.add(cba[i]);
}
rba = new JRadioButton[anz];
ButtonGroup bg = new ButtonGroup();
for (int i=0; i<rba.length; i++)
{
rba[i] = new JRadioButton("Select " + (i+1));
bg.add(rba[i]);
c.add(rba[i]);
}
setSize(380, 120);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args)
{
new AuswahlfeldDemo(4).setVisible(true);
}
}
45
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 56B – 01 – TH – 05
------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (11-1)
Die Klasse JPanel (Package javax.swing)
◇ Diese Klasse dient zur Erzeugung von Gruppierungsfeldern.
Ein Gruppierungsfeld ist ein "innerer" Container, der in erster Linie zur strukturierten Gestaltung des Inhalts von
Fensterbereichen dient.
Mit einem Gruppierungsfeld lassen sich mehrere Komponenten zu einer Komponente zusammenfassen, die dann wie-
derum in einen anderen Container (Top-Level-Container oder ein weiterer "innerer" Container) eingefügt werden kann.
◇ Die Klasse JPanel ist von der Klasse JComponent abgeleitet.
◇ Wie andere Container auch, verwenden JPanel-Objekte einen Layout-Manager. Im Unterschied zu den Top-Level-
Containern ist bei ihnen Flow-Layout als Default eingestellt.
Ein anderes Layout lässt sich gegebenenfalls bei der Objekt-Erzeugung im Konstruktor oder mittels der – von der
Klasse Container geerbten – Methode setLayout() setzen. Allerdings ist ein Setzen des BoxLayouts bei der Objekterzeugung ist nicht möglich.
Die folgende Anweisung JPanel mpan = new JPanel(new BoxLayout(mpan, BoxLayout.Y_AXIS));
führt zur der Compiler-Fehlermeldung "Variable mpan ist nicht initialisiert worden".
◇ JPanel-Objekte verfügen von Haus aus über keine Umrandung.
Bei Bedarf lassen sich aber Umrandungen mit der von der Klasse JComponent geerbten Methode setBorder()
setzen.
◇ Konstruktoren (Auswahl)
◇ Memberfunktionen
Die Klasse JPanel stellt die Methoden ihrer direkten und indirekten Basisklassen JComponent, Container
und Component zur Verfügung.
Sie fügt nur wenige weitere – für die Anwendung i.a. nicht wesentliche – Methoden hinzu.
public JPanel() Erzeugung eines JPanel-Objekts
(Flow-Layout voreingestellt)
public JPanel(LayoutManager layout) Erzeugung eines JPanel-Objekts mit dem durch layout
festgelegten Layout-Manager
46
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 56B – 02 – TH – 03
------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (11-2)
Demonstrationsprogramm zur Klasse JPanel
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class JPanelDemo extends JFrame
{ Container c;
JPanel pan1, pan2, pan3;
public JPanelDemo()
{ super("JPanelDemo");
c=getContentPane();
pan1 = new JPanel();
pan2 = new JPanel();
pan3 = new JPanel(new GridLayout(2,3));
for (int i=1; i<=4; i++)
pan1.add(new JButton("Button " + i));
pan1.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
pan1.setBackground(Color.ORANGE);
Icon javaLogo = new ImageIcon("javalogo52x88.gif");
JLabel lab1 = new JLabel(javaLogo);
JLabel lab2 = new JLabel("Java", SwingConstants.LEFT);
lab2.setBorder(BorderFactory.createEmptyBorder(0,0,0,30));
JLabel lab3 = new JLabel("avaJ", SwingConstants.RIGHT);
lab3.setBorder(BorderFactory.createEmptyBorder(0,30,0,0));
pan2.add(lab2); pan2.add(lab1); pan2.add(lab3);
for (int i=1; i<=6; i++)
pan3.add(new JCheckBox("Auswahl " + i));
Border bord1 = BorderFactory.createLineBorder(Color.GREEN, 5);
Border bord2 = BorderFactory.createTitledBorder(bord1, "Auswahl");
pan3.setBorder(bord2);
c.add(pan1, BorderLayout.NORTH);
c.add(pan2, BorderLayout.CENTER);
c.add(pan3, BorderLayout.SOUTH);
setSize(380, 270);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args)
{ new JPanelDemo().setVisible(true);
}
}
47
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 56C – 01 – TH – 01
------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (12-1)
Die Klasse Box (Package javax.swing)
◇ Diese – direkt von JComponent abgeleitete – Klasse ist eine weitere "innere" Container-Klasse. Sie dient eben-
falls zur Erzeugung von Gruppierungsfeldern.
◇ Defaultmässig ist Box-Layout eingestellt. Dieses Layout kann jedoch nicht verändert werden
Die – indirekt von Container geerbte – Methode setLayout(...) ist so überschrieben, dass sie immer eine
AWTError-Exception wirft.
Gruppierungs-Box.
◇ Die Anordnungs-Achse des verwendeten Box-Layouts (vertikal oder horizontal) ist bei der Objekt-Erzeugung
anzugeben.
◇ Bezüglich der Verwendung als Gruppierungsfelder können Box-Objekte im wesentlichen wie JPanel-Objekte
eingesetzt werden.
Auch Box-Objekte verfügen von Haus aus über keine Umrandung. Mittels der von JComponent geerbten
Methode setBorder(...) lassen sich jederzeit gewünschte Umrandungen setzen.
◇ Als zusätzliche Besonderheit stellt die Klasse Box eine Reihe von statischen Methoden zur Verfügung, mit denen
unsichtbare GUI-Komponenten erzeugt werden können, die sich als Abstands- und Füll-Komponenten im Box-
Layout – auch in Nicht-Box-Containern – einsetzen lassen.
Diese Komponenten sind Objekte der Klasse Box.Filler (innere Klasse von Box), die ebenfalls direkt von der
Klasse JComponent abgeleitet ist.
Prinzipiell können diese Komponenten auch in anderen Layouts verwendet werden, aber ihre wesentliche Bedeutung
haben sie beim BoxLayout.
◇ Konstruktor
◇ Statische Methoden zur Objekterzeugung
◇ Statische Methoden zur Erzeugung unsichtbarer GUI-Komponenten (Auswahl)
public Box(int axis) Erzeugung eines Box-Objekts dessen Layout, die durch axis festgelegte
Anordnungs-Achse besitzt.
Folgende Konstante sind zulässige Werte für axis :
- BoxLayout.X_AXIS (horizontale Anordnung, in einer Zeile)
- BoxLayout.Y_AXIS (vertikale Anordnung, in einer Spalte)
- BoxLayout.LINE_AXIS (für europäische Sprachen : horizontale Anordnung)
- BoxLayout.PAGE_AXIS (für europäische Sprachen : vertikale Anordnung)
public static Box createHorizontalBox() Erzeugung eines Box-Objekts mit horizontaler
Anordnungs-Achse seines Layouts
public static Box createVerticalBox() Erzeugung eines Box-Objekts mit vertikaler
Anordnungs-Achse seines Layouts
public static Component createRigidArea(Dimension d) Erzeugung eines Box.Filler-Objekts
das die durch d definierte feste Grösse
besitzt ( Abstands-Komponente)
public static Component createHorizontalGlue() Erzeugung eines Box.Filler-Objekts variabler
anpassbarer Breite ( horizontale Füll-Komponente)
public static Component createVerticalGlue() Erzeugung eines Box.Filler-Objekts variabler
anpassbarer Höhe ( vertikale Füll-Komponente)
48
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 56C – 03 – TH – 01
------------------------------------------------------------------------------------
Ausgewählte Swing-Komponenten-Klassen (12-3)
Demonstrationsprogramm zur Klasse Box (und zu unsichtbaren GUI-Komponenten)
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
public class BoxDemo extends JFrame
{
public BoxDemo()
{ super("BoxDemo");
Box mbox = new Box(BoxLayout.Y_AXIS);
Box box1 = Box.createHorizontalBox(); // = new Box(BoxLayout.X_AXIS);
Box box2 = Box.createVerticalBox(); // = new Box(BoxLayout.Y_AXIS);
mbox.setBorder(BorderFactory.createLineBorder(Color.BLACK,3));
box1.setBorder(BorderFactory.createLineBorder(Color.GREEN,3));
box2.setBorder(BorderFactory.createLineBorder(Color.RED,3));
box1.setAlignmentX(CENTER_ALIGNMENT);
box2.setAlignmentX(CENTER_ALIGNMENT);
for (int i=1; i<=3; i++)
{ box1.add(Box.createRigidArea(new Dimension(5,0)));
box1.add(new JButton("HB-Button " + i));
}
box1.add(Box.createHorizontalGlue());
box1.setMinimumSize(new Dimension(400, 60));
box1.setMaximumSize(box1.getMinimumSize());
box1.setPreferredSize(box1.getMinimumSize());
box2.add(Box.createVerticalGlue());
for (int i=1; i<=2; i++)
{ box2.add(new JButton("VB-Button " + i));
box2.add(Box.createRigidArea(new Dimension(0,5)));
}
mbox.add(Box.createRigidArea(new Dimension(0,10)));
mbox.add(box1);
mbox.add(Box.createRigidArea(new Dimension(0,10)));
mbox.add(box2);
mbox.add(Box.createRigidArea(new Dimension(0,10)));
add(mbox, BorderLayout.CENTER);
setSize(480, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args)
{ new BoxDemo().setVisible(true);
}
}
49
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 571 – 00 – TH – 02
------------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (1)
Delegation Event Model
◇ In Programmen mit einem grafischen Benutzerinterface findet die Kommunikation zwischen dem Benutzer und dem
Programm mittels Ereignissen (events) statt.
◇ Benutzerinteraktionen mit der graphischen Oberfläche (wie z.B. Anwählen eines Schaltknopfes oder Auswahl eines
Menue-Eintrags mittels Maus oder Tastatur, Schliessen eines Fensters, sonstige Mausbewegungen und Mausklicks,
sonstige Tastatureingaben usw) lösen Ereignisse aus, die als Nachrichten vom Betriebssystem an das Programm gesandt
werden. Auch Änderungen der Größe, der Lage, des Inhalts und des sonstigen Zustands von GUI-Komponenten können
zu Ereignissen in diesem Sinne führen.
Ereignisse können also von unterschiedlichem Typ sein.
◇ Innerhalb eines Java-Programms werden die durch Nachrichten angezeigten Ereignisse als Objekte spezieller Ereignis-
Klassen (event objects) dargestellt.
Diese Ereignis-Objekte kapseln Informationen über das jeweilige Ereignis (z.B. die Ereignisquelle, spezielle Para-
meter, wie Mauskoordinaten, Tastaur-Codes usw)
◇ Die GUI-Komponente an der oder durch die ein Ereignis erzeugt wurde, wird als Ereignisquelle (event source)
bezeichnet. Prinzipiell kann jede Komponente einer graphischen Oberfläche eine derartige Ereignisquelle sein.
◇ Zuständig für die Reaktion auf das Ereignis sind spezielle Ereignisempfänger, die sogenannten Event-Listener.
Dies sind Objekte, die ein zum jeweiligen Ereignis passendes Bearbeitungs-Interface implementieren.
Damit ein Event-Listener-Objekt die von einer bestimmten Ereignisquelle verursachten Ereignisse empfangen kann,
muß es bei dieser Ereignisquelle als Listener registriert sein (Design Pattern Observer !).
Dabei werden einem Listener nur die Ereignisse mitgeteilt, die zu seinem Typ passen, d.h. für die er ein passendes
Bearbeitungs-Interface implementiert hat.
◇ Das Zustellen der einzelnen Ereignisse an die jeweils registrierten Event-Listener erfolgt durch den Aufruf der für den
Ereignis-Typ zuständigen Bearbeitungsfunktion des Listeners (Call Back !). Dieser wird das Ereignis-Objekt als Para-
meter übergeben.
In jedem GUI-Programm ist hierfür ein eigener Thread zuständig, der event-dispatching thread.
◇ Zwischen einer Ereignisquelle und einem Event-Listener muß keine 1:1-Beziehung bestehen.
Bei einer Ereignisquelle können durchaus mehrere Event-Listener registriert sein – sogar für den gleichen Ereignis-Typ.
Das Ereignis wird dann allen bei der Quelle für den jeweiligen Ereignis-Typ registrierten Event-Listenern zugestellt.
Andererseits kann ein Event-Listener auch gleichzeitig bei mehreren Ereignisquellen registriert sein.
◇ Das in Java seit dem JDK 1.1 implementierte Delegation Event Model wird sowohl für AWT-Komponenten als auch
Swing-Komponenten angewendet.
◇ Es ermöglicht eine klare Trennung zwischen dem Programmcode zur Oberflächengestaltung (GUI-Klassen !) und
dem Code zur Ereignisverarbeitung (Event-Listener-Klassen) als Schnittstelle zur Anwendungslogik.
Ereignisquelle 1 event Event-Listener 1
Ereignisquelle 2
Event-Listener 2
Event-Listener 3
event
Ereignisquelle 3
Event-Listener 4
event
event
50
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 572 – 00 – TH – 03
------------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (2)
Ereignis-Klassen
◇ Auszug aus der Hierarchie der Ereignisklassen
◇ Die verschiedenen Event-Klassen implementieren jeweils Memberfunktionen mit denen Informationen, die mit dem
jeweiligen Event-Objekt verknüpft sind, ermittelt werden können.
◇ Die Klasse EventObject, Basisklasse aller Ereignis-Klassen, stellt die folgende Methode zur Verfügung :
Diese Methode wird von allen anderen Ereignis-Klassen geerbt und kann damit für alle Event-Objekte aufgerufen
werden.
◇ Die verschiedenen Ereignis-Klassen sind jeweils bestimmten Ereignisse auslösenden Aktionen zugeordnet.
Beispielsweise wird ein ActionEvent-Objekt durch folgende Aktionen erzeugt :
- Betätigung eines Schaltknopfes
- Selektierung eines Auswahlfeldes
- Auswahl eines Menue- oder Auswahllisten-Eintrags
- Betätigung der RET-Taste
◇ In vielen Fällen kann bei einer Komponente einer bestimmten GUI-Klasse ein Objekt einer bestimmten Ereignis-Klasse
nur durch eine einzige Aktionsart erzeugt werden.
Diese Aktionsart kann bei den verschiedenen GUI-Klassen durchaus unterschiedlich sein.
Es gibt aber auch Ereignis-Klassen, die für mehrere verschiedene Aktionsarten bei der gleichen Komponente zuständig
sind.
Beispielsweise ist die Klasse MouseEvent sowohl für Mausbewegungen (mouse motion events) als auch für alle
sonstigen Mausereignisse (mouse events, wie Knopfbetätigung, Maus-Eintritt, Maus-Austritt in Komponente) zuständig
EventObject
(java.util)
AWTEvent
(java.awt)
ChangeEvent
(javax.swing.event)
ListSelectionEvent
(javax.swing.event)
CaretEvent
(javax.swing.event)
MenuEvent
(javax.swing.event)
ComponentEvent
(java.awt.event)
ActionEvent
(java.awt.event)
ItemEvent
(java.awt.event)
AncestorEvent
(javax.swing.event)
InputEvent
(java.awt.event)
ContainerEvent
(java.awt.event)
WindowEvent
(java.awt.event)
FocusEvent
(java.awt.event)
KeyEvent
(java.awt.event)
MouseEvent
(java.awt.event)
. . . weitere Event-
Klassen
. . . weitere Event-
Klassen
. . . weitere Event-
Klassen
AWT Swing
public Object getSource() Ermittlung der ursprünglichen Ereignisquelle
51
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 573 – 00 – TH – 02
-----------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (3)
Ereignis-Klassen, Forts.
◇ Da auf den verschiedenen GUI-Komponenten jeweils nur spezifische Aktionen ausgeführt werden können, können
diese auch nur Ereignisse ganz bestimmter Klassen auslösen.
Einige Ereignis-Klassen werden bereits in den Basisklassen der JFC-Hierarchie unterstützt. Entsprechende Ereignisse
können daher in allen Komponenten der davon abgeleiteten Klassen ausgelöst werden. Einige GUI-Komponenten und die von ihnen unterstützen Ereignis-Klassen :
◇ Memberfunktionen (Auswahl) einiger Ereignis-Klassen zur Informationsermittlung über das Ereignis :
▻ Klasse AWTEvent
▻ Klasse ActionEvent
▻ Klasse ItemEvent
▻ Klasse WindowEvent
public int getID() Ermittlung der auslösenden Aktionsart (Klassenkonstante !)
public String getActionCommand() Ermittlung der für das Ereignis festgelegten Aktionskennung
public Object getItem() Ermittlung des vom Ereignis betroffenen Objekts
public int getStateChange() Ermittlung des geänderten Zustands (selektiert oder nicht selektiert)
public Window getWindow() Ermittlung des Fensters, das das Ereignis ausgelöst hat
GUI-Klasse unterstützte Ereignis-Klasse auslösende Aktionn Component ComponentEvent Position, Größe oder Sichtbarkeit wurden geändert
FocusEvent Focus wurde erhalten oder verloren
KeyEvent Tastatur wurde betätigt
MouseEvent Maus wurde betätigt oder bewegt
Container ContainerEvent Container-Inhalt wurde verändert
Window WindowEvent Status des Fensters hat sich geändert
JComponent AncestorEvent Umgebender Container hat sich verändert
JButton ActionEvent Schaltknopf wurde betätigt
ChangeEvent Zustand des Schaltknopfes hat sich geändert
JTextField ActionEvent RET-Taste wurde betätigt
CaretEvent Cursorposition hat sich geändert
JTextArea CaretEvent Cursorposition hat sich geändert
JCheckBox ActionEvent Auswahlfeld wurde betätigt
und ChangeEvent Zustand des Auswahlfelds hat sich geändert
JRadioButton ItemEvent Selektionszustand hat sich geändert
JList ListSelectionEvent Selektion wurde geändert
…
52
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 574 – 00 – TH – 03
-----------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (4)
Listener-Interfaces
◇ Die beim Auftritt eines Ereignisses informierten Event-Listener müssen jeweils ereignisspezifisch reagieren können.
Ein Ereignis einer bestimmten Klasse kann nur ein Listener empfangen, der bestimmte zur Ereignis-Klasse passende
Reaktions-Methoden bereitstellt.
Jeder Listener muss ein bestimmtes Interface implementieren.
◇ Zu jeder Ereignis-Klasse ist mindestens ein passendes Listener-Interface definiert. Für einige Ereignis-Klassen gibt es
auch mehrere Listener-Interfaces. Allgemein gilt :
Zur Ereignis-Klasse AbcEvent existiert das Listener-Interface AbcListener.
Beispiele : Ereignisklasse ActionEvent Listener-Interface ActionListener
Ereignisklasse ItemEvent Listener-Interface ItemListener Bei mehreren mit einer Ereignis-Klasse korrespondierenden Listener-Interfaces gilt : Zur Ereignis-Klasse AbcEvent existieren Listener-Interfaces AbcXyzListener
Beispiel : Ereignis-Klasse WindowEvent Listener-Interface WindowListener
WindowFocusListener
WindowStateListener
◇ Die verschiedenen Interfaces sind definiert in den Packages java.awt.event und javax.swing.event.
Hierarchie der EventListener-Interfaces
◇ Alle Listener-Interfaces sind vom Interface EventListener (Package java.util) abgeleitet.
Dieses deklariert keine Methoden sondern ist ein reines Marker-Interface.
◇ Einige Interfaces deklarieren genau eine Methode. Sie sind i.a. sogenannten semantischen Ereignissen zugeordnet.
Andere Interfaces, die i.a. sogenannten Low-Level-Ereignissen zugeordnet sind, deklarieren mehrere Methoden.
Eine Event-Listener-Klasse muß alle Methoden des Interfaces, das sie implementiert, definieren.
Die jeweilige Methode enthält den vom Programm als Reaktion auf das Ereignis auszuführenden Code
( Event-Handler)
Die Information eines Event-Listeners über ein eingetretenes Ereignis erfolgt durch den Aufruf einer dieser Methoden
als Callback.
◇ Alle Methoden besitzen genau einen Parameter von der jeweiligen zugehörigen Ereignis-Klasse.
53
Beim Aufruf einer Methode wird ihr das ausgelöste Ereignis-Objekt als aktueller Parameter übergeben.
◇ Einige Listener-Interfaces als Beispiele :
▻ Interface ActionListener (Package java.awt.event)
▻ Interface ItemListener (Package java.awt.event)
▻ Interface WindowListener (Package java.awt.event), unvollständig
public void actionPerformed(ActionEvent e) aufgerufen, wenn ein ActionEvent auftritt
public void itemStateChanged(ItemEvent e) aufgerufen, wenn ein ItemEvent auftritt
public void windowClosing(WindowEvent e) aufgerufen, wenn Fenster geschlossen werden soll
public void windowClosed(WindowEvent e) aufgerufen, wenn Fenster geschlossen wurde
public void windowActivated(WindowEvent e) aufgerufen, wenn Fenster aktiviert wurde
public void windowDeactivated(WindowEvent e) aufgerufen, wenn Fenster deaktiviert wurde
public void windowIconified(WindowEvent e) aufgerufen, wenn Fenster minimiert wurde
54
Key-Events Unter Windows werden alle Tastatureingaben an die fokussierte Komponente gesendet. Ein Empfänger für Key-Events muß
das Interface KeyListener implementieren und bekommt Events des Typs KeyEvent übergeben. KeyEvent erweitert
die Klasse InputEvent, die ihrerseits aus ComponentEvent abgeleitet ist, und stellt neben getID und getSource
eine ganze Reihe von Methoden zur Verfügung, mit denen die Erkennung und Bearbeitung der Tastencodes vereinfacht wird.
Die Registrierung von Key-Events erfolgt mit der Methode addKeyListener, die auf allen Objekten des Typs
Component oder daraus abgeleiteten Klassen zur Verfügung steht:
public void addKeyListener(KeyListener l) java.awt.Component
Das Interface KeyListener definiert drei unterschiedliche Methoden:
public abstract void keyPressed(KeyEvent e)
public abstract void keyReleased(KeyEvent e)
public abstract void keyTyped(KeyEvent e)
Mouse-Events l Ein Mouse-Event entsteht, wenn der Anwender innerhalb der Client-Area des Fensters eine der Maustasten drückt oder
losläßt. Dabei reagiert das Programm sowohl auf Klicks der linken als auch - falls vorhanden - der rechten Maustaste und zeigt
an, welche der Umschalttasten [STRG], [ALT], [UMSCHALT] oder [META] während des Mausklicks gedrückt waren. Des
weiteren ist es möglich, zwischen einfachen und doppelten Mausklicks zu unterscheiden.
Ein Empfänger für Mouse-Events muß das Interface MouseListener implementieren und bekommt Events des Typs
MouseEvent übergeben. MouseEvent erweitert die Klasse InputEvent und stellt neben getID und getSource
eine Reihe zusätzlicher Methoden zur Verfügung, die wichtige Informationen liefern. Die Registrierung der Empfängerklasse
erfolgt mit der Methode addMouseListener, die in allen Klassen zur Verfügung steht, die aus Component abgeleitet
wurden: public void addMouseListener(MouseListener l)
Tabelle 29.3 gibt eine Übersicht der Methoden von MouseListener und erklärt ihre Bedeutung:
Ereignismethode Bedeutung
mousePressed Eine Maustaste wurde gedrückt.
mouseReleased Die gedrückte Maustaste wurde losgelassen.
mouseClicked Eine Maustaste wurde gedrückt und wieder losgelassen. Diese Methode wird nach
mouseReleased aufgerufen.
mouseEntered Der Mauszeiger wurde in den Client-Bereich der auslösenden Komponente hineinbewegt.
mouseExited Der Mauszeiger wurde aus dem Client-Bereich der auslösenden Komponente herausbewegt.
55
FACHHOCHSCHULE MUENCHEN FAKULTÄT ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 575 – 00 – TH – 04
-----------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (5)
Listener-Adapter-Klassen
◇ Eine Klasse, die ein Listener-Interface implementiert, dass mehrere Methoden deklariert, muss sämtliche Metho-
den definieren, auch wenn in der speziellen Anwendung nur eine von ihnen benötigt wird.
◇ Zur Vereinfachung der Definition von Listener-Klassen existieren für derartige Interfaces Adapter-Klassen.
Es handelt sich bei Ihnen um abstrakte Klassen, die sämtliche Methoden des Interfaces mit leerer Funktionalität
implementieren.
Statt eine Listener-Klasse das jeweilige Listener-Interface direkt implementieren zu lassen, leitet man die Klasse von
der zugehörigen Adapter-Klasse ab. Die Klasse muß dann lediglich die im konkreten Fall benötigte Methode über-
schreiben.
◇ Wenn zum Listener-Interface AbcListener eine Adapter-Klasse existiert, lautet ihr Name AbcAdapter. Beispiel : Listener-Interface WindowListener Listener-Adapter WindowAdapter
Listener-Klassen
◇ Sie müssen das Listener-Interface, das zu der Ereignis-Klasse, deren Objekte sie empfangen sollen, gehört, implemen-
tieren.
Eine Listener-Klasse kann auch mehrere Listener-Interfaces implementieren und damit auf Ereignisse unterschied-
licher Klassen reagieren.
◇ Eine Listener-Klasse kann das oder die Listener-Interfaces
▻ entweder direkt implementieren
▻ oder von einer zugehörigen Adapter-Klasse abgeleitet werden.
◇ Zur programmtechnischen Realisierung eine Listener-Klasse existieren folgende Möglichkeiten : (siehe Bspiele)
▻ Realisierung der Listener-Klasse als innere Klasse
▻ Realisierung der Listener-Klasse als lokale Klasse oder anonyme Klasse
▻ Realisierung der Listener-Klasse als Top-Level-Klasse
▻ Verwendung der Container-Klasse als Listener-Klasse
Implementierung einer Ereignisverarbeitung im Anwender-Code
◆ Definition einer geeigneten Event-Listener-Klasse.
In der (bzw den) zu implementierenden Interface-Methode(n) (Event-Handler) ist die Programmfunktionalität zu
realisieren, die als Reaktion auf den Eintritt eines Ereignisses der betreffenden Art vorgesehen ist.
◆ Erzeugung eines Objekts dieser Event-Listener-Klasse (Event-Listener-Objekt).
◆ Registrierung des Event-Listener-Objekts bei der auf Ereignisse zu "überwachenden" GUI-Komponente. Hierfür stellen die GUI-Komponenten für die von ihnen unterstützten Listener-Typen entsprechende Registrierungs-
funktionen zur Verfügung :
Für EventListener vom Typ AbcListener Funktion void addAbcListener(AbcListener lis) Beispiel : Klasse JButton für ActionListener-Objekte (geerbt von der Klasse AbstractButton) :
◆ Gegebenenfalls Festlegung von spezifischen Informationen, die einem Ereignis-Objekt übergeben werden. Beispiel : Klasse JButton : Setzen einer Aktionskennung (action command) für ActionListener-Objekte
(geerbt von der Klasse AbstractButton) :
public void addActionListener(ActionListener lis) Registrierung des Action-Listener-Objects lis
public void setActionCommand(String cmd) Setzen der Aktionskennung cmd
56
Beispiele Variante 1: Implementierung eines EventListener-Interfaces Bei der ersten Variante gibt es nur eine einzige Klasse, Listing2802. Sie ist einerseits eine Ableitung der Klasse JFrame,
um ein Fenster auf dem Bildschirm darzustellen und zu beschriften. Andererseits implementiert sie das Interface
KeyListener, das die Methoden keyPressed, keyReleased und keyTyped definiert. Der eigentliche Code zur
Reaktion auf die Taste [ESC] steckt in der Methode keyPressed, die immer dann aufgerufen wird, wenn eine Taste
gedrückt wurde. Mit der Methode getKeyCode der Klasse KeyEvent wird auf den Code der gedrückten Taste zugegriffen
und dieser mit der symbolischen Konstante VK_ESCAPE verglichen. Stimmen beide überein, wurde [ESC] gedrückt, und das
Programm kann beendet werden.
001 /* Listing2802.java */
002
003 import java.awt.*;
004 import java.awt.event.*;
005
006 public class Listing2802
007 extends JFrame
008 implements KeyListener
009 {
010 public static void main(String[] args)
011 {
012 Listing2802 wnd = new Listing2802();
013 }
014
015 public Listing2802()
016 {
017 super("Nachrichtentransfer");
018 setBackground(Color.lightGray);
019 setSize(300,200);
020 setLocation(200,100);
021 setVisible(true);
022 addKeyListener(this);
023 }
024
025 public void paint(Graphics g)
026 {
027 g.setFont(new Font("Serif",Font.PLAIN,18));
028 g.drawString("Zum Beenden bitte ESC drücken...",10,50);
029 }
030
031 public void keyPressed(KeyEvent event)
032 {
033 if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
034 setVisible(false);
035 dispose();
036 System.exit(0);
037 }
038 }
039
040 public void keyReleased(KeyEvent event)
041 {
042 }
043
044 public void keyTyped(KeyEvent event)
045 {
046 }
047 }
Listing2802.java
57
Listing 28.2: Implementieren eines Listener-Interfaces
Die Verbindung zwischen der Ereignisquelle (in diesem Fall der Fensterklasse Listing2802) und dem Ereignisempfänger
(ebenfalls die Klasse Listing2802) erfolgt über den Aufruf der Methode addKeyListener der Klasse JFrame. Alle
Tastaturereignisse werden dadurch an die Fensterklasse selbst weitergeleitet und führen zum Aufruf der Methoden
keyPressed, keyReleased oder keyTyped des Interfaces KeyListener. Diese Implementierung ist sehr
naheliegend, denn sie ist einfach zu implementieren und erfordert keine weiteren Klassen. Nachteilig ist dabei allerdings:
lEs besteht keine Trennung zwischen GUI-Code und Applikationslogik. Dies kann große Programme unübersichtlich
und schwer wartbar machen.
l Für jeden Ereignistyp muss eine passende Listener-Klasse registriert werden. Da viele der EventListener-
Interfaces mehr als eine Methode definieren, werden dadurch schnell viele leere Methodenrümpfe in der
Fensterklasse zu finden sein. In diesem Beispiel sind es schon keyReleased und keyTyped, bei zusätzlichen
Interfaces würden schnell weitere hinzukommen.
Es bleibt festzuhalten, dass diese Technik bestenfalls für kleine Programme geeignet ist, die nur begrenzt erweitert werden
müssen. Durch die Vielzahl leerer Methodenrümpfe können aber auch kleine Programme schnell unübersichtlich werden.
Variante 2: Lokale und anonyme Klassen Die zweite Alternative bietet eine bessere Lösung. Sie basiert auf der Verwendung lokaler bzw. anonymer Klassen und kommt
ohne die Nachteile der vorigen Version aus. Sie ist das in der Dokumentation des JDK empfohlene Entwurfsmuster für das
Event-Handling in kleinen Programmen oder bei Komponenten mit einfacher Nachrichtenstruktur. Vor ihrem Einsatz sollte
man allerdings das Prinzip lokaler und anonymer Klassen kennenlernen, das mit dem JDK 1.1 in Java eingeführt und in
Abschnitt 10.1 vorgestellt wurde. Wer diesen Abschnitt noch nicht gelesen hat, sollte das jetzt nachholen.
Lokale Klassen
Die Anwendung lokaler Klassen für die Ereignisbehandlung besteht darin, mit ihrer Hilfe die benötigten EventListener
zu implementieren. Dazu wird in dem GUI-Objekt, das einen Event-Handler benötigt, eine lokale Klasse definiert und aus
einer passenden Adapterklasse abgeleitet. Nun braucht nicht mehr das gesamte Interface implementiert zu werden (denn die
Methodenrümpfe werden ja aus der Adapterklasse geerbt), sondern lediglich die tatsächlich benötigten Methoden. Da die
lokale Klasse zudem auf die Membervariablen und Methoden der Klasse zugreifen kann, in der sie definiert wurde, lassen sich
auf diese Weise sehr schnell die benötigten Ereignisempfänger zusammenbauen.
Das folgende Beispiel definiert eine lokale Klasse MyKeyListener, die aus KeyAdapter abgeleitet wurde und auf diese
Weise das KeyListener-Interface implementiert. Sie überlagert lediglich die Methode keyPressed, um auf das Drücken
einer Taste zu reagieren. Als lokale Klasse hat sie außerdem Zugriff auf die Methoden der umgebenden Klasse und kann somit
durch Aufruf von setVisible und dispose das Fenster, in dem sie als Ereignisempfänger registriert wurde, schließen.
Die Registrierung der lokalen Klasse erfolgt durch Aufruf von addKeyListener, bei dem gleichzeitig eine Instanz der
lokalen Klasse erzeugt wird. Als lokale Klasse ist MyKeyListener überall innerhalb von Listing2803 sichtbar und kann
an beliebiger Stelle instanziert werden.
001 /* Listing2803.java */
002
003 import java.awt.*;
004 import java.awt.event.*;
import javax.swing.*;
005
006 public class Listing2803
007 extends JFrame
008 {
009 public static void main(String[] args)
010 {
011 Listing2803 wnd = new Listing2803();
012 }
013
014 public Listing2803()
015 {
016 super("Nachrichtentransfer");
017 setBackground(Color.lightGray);
018 setSize(300,200);
019 setLocation(200,100);
020 setVisible(true);
021 addKeyListener(new MyKeyListener());
022 }
023
58
024 public void paint(Graphics g)
025 {
026 g.setFont(new Font("Serif",Font.PLAIN,18));
027 g.drawString("Zum Beenden bitte ESC drücken...",10,50);
028 }
029
030 class MyKeyListener
031 extends KeyAdapter
032 {
033 public void keyPressed(KeyEvent event)
034 {
035 if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
036 setVisible(false);
037 dispose();
038 System.exit(0);
039 }
040 }
041 }
042 }
Listing 28.3: Verwendung lokaler Klassen
Der Vorteil dieser Vorgehensweise ist offensichtlich: es werden keine unnützen Methodenrümpfe erzeugt, aber trotzdem
verbleibt der Ereignisempfängercode wie im vorigen Beispiel innerhalb der Ereignisquelle. Dieses Verfahren ist also immer
dann gut geeignet, wenn es von der Architektur oder der Komplexität der Ereignisbehandlung her sinnvoll ist, Quelle und
Empfänger zusammenzufassen.
Anonyme Klassen Das folgende Beispiel ist eine leichte Variation des vorigen. Es zeigt die Verwendung einer anonymen Klasse, die aus
KeyAdapter abgeleitet wurde, als Ereignisempfänger. Zum Instanzierungszeitpunkt erfolgt die Definition der überlagernden
Methode keyPressed, in der der Code zur Reaktion auf das Drücken der Taste [ESC] untergebracht wird.
001 /* Listing2804.java */
002
003 import java.awt.*;
004 import java.awt.event.*;
import javax.swing.*
005
006 public class Listing2804
007 extends JFrame
008 {
009 public static void main(String[] args)
010 {
011 Listing2804 wnd = new Listing2804();
012 }
013
014 public Listing2804()
015 {
016 super("Nachrichtentransfer");
017 etBackground(Color.lightGray);
018 setSize(300,200);
019 setLocation(200,100);
020 setVisible(true);
021 addKeyListener(
022 new KeyAdapter() {
023 public void keyPressed(KeyEvent event)
024 {
025 if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
026 setVisible(false);
027 dispose();
028 System.exit(0);
029 }
030 }
031 }
032 );
033 }
034
59
035 public void paint(Graphics g)
036 {
037 g.setFont(new Font("Serif",Font.PLAIN,18));
038 g.drawString("Zum Beenden bitte ESC drücken...",10,50);
039 }
040 }
Listing 28.4: Verwendung einer anonymen Klasse als Ereignishandler
Vorteilhaft bei dieser Vorgehensweise ist der verminderte Aufwand, denn es muss keine separate Klassendefinition angelegt
werden. Statt dessen werden die wenigen Codezeilen, die zur Anpassung der Adapterklasse erforderlich sind, dort eingefügt,
wo die Klasse instanziert wird, nämlich beim Registrieren des Nachrichtenempfängers. Anonyme Klassen haben einen
ähnlichen Einsatzbereich wie lokale, empfehlen sich aber vor allem, wenn sehr wenig Code für den Ereignisempfänger
benötigt wird. Bei aufwendigeren Ereignisempfängern ist die explizite Definition einer benannten Klasse dagegen
vorzuziehen.
Variante 3: Trennung von GUI- und Anwendungscode Wir hatten am Anfang darauf hingewiesen, daß in größeren Programmen eine Trennung zwischen Programmcode, der für die
Oberfläche zuständig ist, und solchem, der für die Anwendungslogik zuständig ist, wünschenswert wäre. Dadurch wird eine
bessere Modularisierung des Programms erreicht, und der Austausch oder die Erweiterung von Teilen des Programms wird
erleichtert.
Das Delegation Event Model wurde auch mit dem Designziel entworfen, eine solche Trennung zu ermöglichen
bzw. zu erleichtern. Der Grundgedanke dabei war es, auch Nicht-Komponenten die Reaktion auf GUI-Events zu
ermöglichen. Dies wurde dadurch erreicht, daß jede Art von Objekt als Ereignisempfänger registriert werden kann,
solange es die erforderlichen Listener-Interfaces implementiert. Damit ist es möglich, die Anwendungslogik
vollkommen von der grafischen Oberfläche abzulösen und in Klassen zu verlagern, die eigens für diesen Zweck
entworfen wurden.
Hinweis
Das nachfolgende Beispiel zeigt diese Vorgehensweise, indem es unser Beispielprogramm in die drei Klassen
Listing2805, MainFrameCommand und MainFrameGUI aufteilt. Listing2805 enthält nur noch die main-
Methode und dient lediglich dazu, die anderen beiden Klassen zu instanzieren. MainFrameGUI realisiert die GUI-
Funktionalität und stellt das Fenster auf dem Bildschirm dar. MainFrameCommand spielt die Rolle des
Kommandointerpreters, der immer dann aufgerufen wird, wenn im Fenster ein Tastaturereignis aufgetreten ist.
Die Verbindung zwischen beiden Klassen erfolgt durch Aufruf der Methode addKeyListener in MainFrameGUI, an die
das an den Konstruktor übergebene MainFrameCommand-Objekt weitergereicht wird. Dazu ist es erforderlich, daß das
Hauptprogramm den Ereignisempfänger cmd zuerst instanziert, um ihn bei der Instanzierung des GUI-Objekts gui übergeben
zu können.
Umgekehrt benötigt natürlich auch das Kommando-Objekt Kenntnis über das GUI-Objekt, denn es soll ja das
zugeordnete Fenster schließen und das Programm beenden. Der scheinbare Instanzierungskonflikt durch diese zirkuläre
Beziehung ist aber in Wirklichkeit gar keiner, denn bei jedem Aufruf einer der Methoden von MainFrameCommand
wird an das KeyEvent-Objekt der Auslöser der Nachricht übergeben, und das ist in diesem Fall stets das
MainFrameGUI-Objekt gui. So kann innerhalb des Kommando-Objekts auf alle öffentlichen Methoden des GUIObjekts
zugegriffen werden.
Tip 001 /* Listing2805.java */
002
003 import java.awt.*;
004 import java.awt.event.*;
005 import javax.swing.*
006 public class Listing2805
007 {
008 public static void main(String[] args)
009 {
010 MainFrameCommand cmd = new MainFrameCommand();
011 MainFrameGUI gui = new MainFrameGUI(cmd);
012 }
013 }
014
60
015 class MainFrameGUI
016 extends JFrame
017 {
018 public MainFrameGUI(KeyListener cmd)
019 {
020 super("Nachrichtentransfer");
021 setBackground(Color.lightGray);
022 setSize(300,200);
023 setLocation(200,100);
024 setVisible(true);
025 addKeyListener(cmd);
026 }
027
028 public void paint(Graphics g)
029 {
030 g.setFont(new Font("Serif",Font.PLAIN,18));
031 g.drawString("Zum Beenden bitte ESC drücken...",10,50);
032 }
033 }
034
035 class MainFrameCommand
036 implements KeyListener
037 {
038 public void keyPressed(KeyEvent event)
039 {
040 JFrame source = (JFrame)event.getSource();
041 if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
042 source.setVisible(false);
043 source.dispose();
044 System.exit(0);
045 }
046 }
047
048 public void keyReleased(KeyEvent event)
049 {
050 }
051
052 public void keyTyped(KeyEvent event)
053 {
054 }
055 }
Listing 28.5: Trennung von GUI- und Anwendungslogik
Diese Designvariante ist vorwiegend für größere Programme geeignet, bei denen eine Trennung von Programmlogik und
Oberfläche sinnvoll ist. Für sehr kleine Programme oder solche, die wenig Ereigniscode haben, sollte eher eine der vorherigen
Varianten angewendet werden, wenn diese zu aufwendig ist. Sie entspricht in groben Zügen dem Mediator-Pattern, das in
"Design-Patterns" von Gamma et al. beschrieben wird.
Natürlich erhebt das vorliegende Beispielprogramm nicht den Anspruch, unverändert in ein sehr großes Programm
übernommen zu werden. Es soll lediglich die Möglichkeit der Trennung von Programmlogik und Oberfläche in einem großen
Programm mit Hilfe der durch das Event-Handling des JDK 1.1 vorgegebenen Möglichkeiten aufzeigen. Eine sinnvolle
Erweiterung dieses Konzepts könnte darin bestehen, weitere Modularisierungen vorzunehmen (z.B. analog dem MVC-Konzept
von Smalltalk, bei dem GUI-Anwendungen in Model-, View- und Controller-Layer aufgesplittet werden, oder auch durch
Abtrennen spezialisierter Kommandoklassen). Empfehlenswert ist in diesem Zusammenhang die Lektüre der
JDKDokumentation, die ein ähnliches Beispiel in leicht veränderter Form enthält.
61
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 576 – 00 – TH – 02
-----------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (6)
Demonstrationsprogramm zum Interface ActionListener
// ColorChangeDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ColorChangeDemo extends JFrame
{
Container c;
JButton but;
public ColorChangeDemo()
{
super("ColorChangeDemo");
c=getContentPane();
c.setLayout(new FlowLayout());
but = new JButton("Change Backgroundcolor");
c.add(but);
// ActionListener-Klasse als anonyme Klasse
ActionListener actlis = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
float rwert = (float)Math.random();
float gwert = (float)Math.random();
float bwert = (float)Math.random();
c.setBackground(new Color(rwert, gwert, bwert));
}
};
but.addActionListener(actlis);
setSize(300, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args)
{
new ColorChangeDemo().setVisible(true);
}
}
62
FACHHOCHSCHULE MUENCHEN FACHBEREICH ELEKTROTECHNIK UND INFORMATIONSTECHNIK
BEREICH DATENTECHNIK V – JV – 577 – 00 – TH – 01
-----------------------------------------------------------------------------------
Ereignisverarbeitung in JFC-GUI-Komponenten (6)
Demonstrationsprogramm zur Adapter-Klasse WindowAdapter
// WindowClosingDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class WindowClosingDemo extends JFrame
{ Container c;
JLabel lab;
JCheckBox cb1, cb2;
public WindowClosingDemo()
{ super("Window Closing Demo");
c = getContentPane();
c.setLayout(new FlowLayout());
lab = new JLabel("Zum Schliessen des Fensters bitte " +
"beide Auswahlfelder selektieren");
lab.setBorder(BorderFactory.createEmptyBorder(10, 0, 25, 0));
cb1 = new JCheckBox("Auswahl 1");
cb2 = new JCheckBox("Auswahl 2");
c.add(lab);
c.add(cb1);
c.add(cb2);
addWindowListener(new ClosingListener());
setSize(400, 150);
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
}
// WindowListener-Klasse als innere Klasse
public class ClosingListener extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{ if (cb1.isSelected() && cb2.isSelected())
{ e.getWindow().dispose();
System.exit(0);
}
else
JOptionPane.showMessageDialog(c, "Vor dem Schliessen " +
"beide Auswahlfelder selektieren");
}
}
public static void main(String[] args)
{ new WindowClosingDemo().setVisible(true);
}
}
63
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 56C – 03 – TH – 01
------------------------------------------------------------------------------------
Komplexe Swing-Komponenten-Klassen (1)
JList Die Klasse JList dient dazu, Listen von Werten darzustellen, aus denen der Anwender einen oder mehrere Einträge
auswählen kann. Im Gegensatz zur AWT-Klasse List kann sie nicht nur Strings, sondern beliebige Objekte enthalten. Auch
die Darstellung der Listenelemente auf dem Bildschirm kann weitgehend frei gestaltet werden. Wir wollen uns die wichtigsten
Eigenschaften von JList ansehen und dazu zunächst mit den Konstruktoren beginnen:
public JList()
public JList(Object[] listData)
public JList(Vector listData)
public JList(ListModel dataModel)
Der parameterlose Konstruktor erzeugt eine leere Liste. Wird ein Array oder Vector übergeben, erzeugt JList aus dessen
Daten ein Listenmodell und benutzt es zur Darstellung. Schließlich kann auch direkt eine Instanz der Klasse ListModel
übergeben werden, um den Inhalt der Liste zu definieren.
Ähnlich wie JTextArea und andere Swing-Komponenten besitzt JList keine eigene Funktionalität zum
Scrollen der Daten, falls diese nicht vollständig auf den Bildschirm passen. Eine JList wird daher meist in eine
JScrollPane eingebettet, bevor sie zu einem GUI-Container hinzugefügt wird.
Hinweis
Selektieren von Elementen
Die meisten Methoden der Klasse JList haben mit der Selektion der Listenelemente zu tun. Eine Liste kann sowohl Einzel als
auch Mehrfachselektion unterstützen: public int getSelectionMode()
public void setSelectionMode(int selectionMode)
Mit setSelectionMode wird der Selektionsmodus verändert. Als Argument kann eine der folgenden Konstanten der
Klasse ListSelectionModel übergeben werden:
l SINGLE_SELECTION: Es kann maximal ein Element ausgewählt werden
l SINGLE_INTERVAL_SELECTION: Es können mehrere Elemente eines zusammenhängenden Bereichs
ausgewählt werden
l MULTIPLE_INTERVAL_SELECTION: Eine beliebige Auswahl von Elementen kann selektiert werden
getSelectionMode liefert den aktuellen Selektionsmodus. Es gibt eine Reihe von Methoden, um Informationen über die
derzeit selektierten Elemente zu beschaffen: public int getSelectedIndex()
public int[] getSelectedIndices()
public Object getSelectedValue()
public Object[] getSelectedValues()
public boolean isSelectedIndex(int index)
public boolean isSelectionEmpty()
public int getAnchorSelectionIndex()
public int getLeadSelectionIndex()
getSelectedIndex liefert den Index des selektierten Elements, falls der Selektionsmodus SINGLE_SELECTION ist.
Können mehrere Elemente ausgewählt werden, liefert getSelectedIndices ein Array mit den Indizes aller selektierten
Elemente. getSelectedValue und getSelectedValues arbeiten in analoger Weise, liefern aber statt der Indizes die
selektierten Elemente zurück. Mit isSelectedIndex kann geprüft werden, ob das Element mit dem angegebenen Index
gerade selektiert ist, und isSelectionEmpty prüft, ob mindestens ein Element selektiert wurde.
Als "Anchor" und "Lead" bezeichnet Swing in einem zusammenhängend markierten Bereich das jeweils zuerst und zuletzt
markierte Element. Das zuletzt markierte Element ist gleichzeitig aktuelles Element. Mit getAnchorSelectionIndex
und getLeadSelectionIndex kann auf "Anchor" und "Lead" zugegriffen werden, wenn der Selektionsmodus
SINGLE_INTERVAL_SELECTION ist.
Zusätzlich gibt es Methoden, um die Selektion programmgesteuert zu verändern: public void clearSelection()
public void setSelectedIndex(int index)
public void setSelectedIndices(int[] indices)
public void setSelectionInterval(int anchor, int lead)
public void addSelectionInterval(int anchor, int lead)
public void removeSelectionInterval(int index0, int index1)
64
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 56C – 03 – TH – 01
------------------------------------------------------------------------------------
Komplexe Swing-Komponenten-Klassen (2)
Mit clearSelection wird die Selektion gelöscht. Mit setSelectedIndex kann ein einzelnes Element selektiert
werden, mit setSelectedIndices eine Menge von Elementen. Mit setSelectionInterval,
addSelectionInterval und removeSelectionInterval können Selektionen auch bereichsweise hinzugefügt und
gelöscht werden.
Wird die Selektion geändert, versendet eine JList ein ListSelectionEvent an alle registrierten Listener. Um im
Programm auf Änderungen zu reagieren, ist also lediglich das Interface ListSelectionListener des Pakets
javax.swing.event zu implementieren und durch Aufruf von addListSelectionListener bei der JList zu
registrieren. Jede Selektionsänderung führt dann zum Aufruf der Methode valueChanged.
Den Listeninhalt dynamisch verändern
Etwas mehr Aufwand als beim AWT-Pendant muß getrieben werden, wenn der Inhalt einer JList nach der Instanzierung
modifiziert werden soll. In diesem Fall kann nicht mehr mit dem automatisch erzeugten Listenmodel gearbeitet werden,
sondern es muß selbst eines erzeugt werden. Das Modell einer JList muß stets das Interface ListModel implementieren
und der Liste durch Versenden eines ListDataEvent jede Datenänderung mitteilen. Eine für viele Zwecke ausreichende
Implementierung steht mit der Klasse DefaultListModel zur Verfügung. Ihre Schnittstelle entspricht der Klasse Vector
und alle erforderlichen Änderungsbenachrichtigungen werden automatisch verschickt. Die wichtigsten
Methoden von DefaultListModel sind:
public void clear()
public void addElement(Object obj)
public void removeElementAt(int index)
public int size()
public Object elementAt(int index)
Soll eine Liste mit einem benutzerdefinierten Modell arbeiten, wird dieses einfach manuell erzeugt und an den Konstruktor
übergeben. Alle Einfügungen, Löschungen und Änderungen von Daten werden dann an diesem Modell vorgenommen. Durch
Aufruf von getModel kann auf einfache Weise auf das Modell einer JList zugegriffen werden.
Beispiel
Zum Abschluss wollen wir uns ein Beispiel ansehen. Das folgende Programm instanziert eine JList durch Übergabe eines
String-Arrays. Bei jedem Drücken des Buttons "Ausgabe" gibt es die Liste der selektierten Elemente auf der Konsole aus: 001 /* Listing3710.java */
002
003 import java.awt.*;
004 import java.awt.event.*;
005 import javax.swing.*;
006
007 public class Listing3710
008 extends JFrame
009 implements ActionListener
010 {
011 static final String[] DATA = {
012 "Hund", "Katze", "Meerschweinchen", "Tiger", "Maus",
013 "Fisch", "Leopard", "Schimpanse", "Kuh", "Pferd",
014 "Reh", "Huhn", "Marder", "Adler", "Nilpferd"
015 };
016
017 private JList list;
018
019 public Listing3710()
020 {
021 super("JList");
022
023 Container cp = getContentPane();
024 //Liste
025 list = new JList(DATA);
026 list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
029 list.setSelectedIndex(2);
65
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK V – JV – 56C – 03 – TH – 01
------------------------------------------------------------------------------------
Komplexe Swing-Komponenten-Klassen (3)
030 cp.add(new JScrollPane(list), BorderLayout.CENTER);
031 //Ausgabe-Button
032 JButton button = new JButton("Ausgabe");
033 button.addActionListener(this);
034 cp.add(button, BorderLayout.SOUTH);
035 }
036
037 public void actionPerformed(ActionEvent event)
038 {
039 String cmd = event.getActionCommand();
040 if (cmd.equals("Ausgabe")) {
041 System.out.println("---");
042 ListModel lm = list.getModel();
043 int[] sel = list.getSelectedIndices();
044 for (int i = 0; i < sel.length; ++i) {
045 String value = (String)lm.getElementAt(sel[i]);
046 System.out.println(" " + value);
047 }
048 }
049 }
050
051 public static void main(String[] args)
052 {
053 Listing3710 frame = new Listing3710();
054 frame.setLocation(100, 100);
055 frame.setSize(200, 200);
056 frame.setVisible(true);
057 }
058 }
Listing 37.10: Die Klasse JList
Die Programmausgabe ist:
66
Listing3710 mit DefaultListModel //Das interne ListModel verfügt nur über die Methoden getSize u. getElementAt
//Falls man z. auch Einfügen und Löschen will, muss das DefaultListModel oder
//ein eigenes ListModel verwendet werden
package list;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Listing3710
extends JFrame
implements ActionListener
{
//Membervariable
static final String[] DATA = {
"Hund", "Katze", "Meerschweinchen", "Tiger", "Maus",
"Fisch", "Leopard", "Schimpanse", "Kuh", "Pferd",
"Reh", "Huhn", "Marder", "Adler", "Nilpferd"
};
private JList list=null;
//Default-ListModel, Schnittstelle entspricht der Klasse Vector
private DefaultListModel lm= new DefaultListModel();
private JTextField jTextField1 = new JTextField();
public Listing3710()
{
super("JList-Demo DefaultListModel");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
//Liste
list = new JList(lm/*DATA*/);
list.setModel(lm);
for(int i=0;i<DATA.length;i++)
{
lm.addElement(DATA[i]);
}
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setSelectedIndex(2);
cp.add(new JScrollPane(list), BorderLayout.CENTER);
//Ausgabe-Button
JButton button = new JButton("Ausgabe+Delete");
button.addActionListener(this);
cp.add(button, BorderLayout.SOUTH);
}
public void actionPerformed(ActionEvent event)
{
String cmd = event.getActionCommand();
if (cmd.equals("Ausgabe+Delete")) {
System.out.println("---");
//ListModel lm = list.getModel();
int[] sel = list.getSelectedIndices();
for (int i = 0; i < sel.length; ++i) {
String value = (String)lm.getElementAt(sel[i]);
System.out.println(" " + value);
67
lm.removeElementAt(sel[i]); //nur bei DefaultListModel
}
}
}
public static void main(String[] args)
{
Listing3710 frame = new Listing3710();
frame.setLocation(100, 100);
frame.setSize(200, 200);
frame.setVisible(true);
}
}
68
FACHHOCHSCHULE MUENCHEN FAKULTÄT FÜR ELEKTROTECHNIK UND INFORMATIONSTECHNIK
FG TECHNISCHE INFORMATIK
------------------------------------------------------------------------------------
Entwurfsmuster (design-pattern) mit GUI-Bezug
Design-Patterns (oder Entwurfsmuster) sind eine der wichtigsten und interessantesten Entwicklungen der objektorientierten
Programmierung der letzten Jahre. Basierend auf den Ideen des Architekten Christopher Alexander wurden sie durch das Buch
"Design-Patterns - Elements of Reusable Object-Oriented Software" von Erich Gamma, Richard Helm, Ralph Johnson und
John Vlissides 1995 einer breiten Öffentlichkeit bekannt.
Als Design-Patterns bezeichnet man (wohlüberlegte) Designvorschläge für den Entwurf objektorientierter Softwaresysteme.
Ein Design-Pattern deckt dabei ein ganz bestimmtes Entwurfsproblem ab und beschreibt in rezeptartiger Weise das
Zusammenwirken von Klassen, Objekten und Methoden. Meist sind daran mehrere Algorithmen und/oder Datenstrukturen
beteiligt. Design-Patterns stellen wie Datenstrukturen oder Algorithmen vordefinierte Lösungen für konkrete
Programmierprobleme dar, allerdings auf einer höheren Abstraktionsebene.
Einer der wichtigsten Verdienste standardisierter Design-Patterns ist es, Softwaredesigns Namen zu geben. Zwar ist es in der
Praxis nicht immer möglich oder sinnvoll, ein bestimmtes Design-Pattern in allen Details zu übernehmen. Die konsistente
Verwendung ihrer Namen und ihres prinzipiellen Aufbaus erweitern jedoch das Handwerkszeug und die
Kommunikationsfähigkeit des OOP-Programmierers beträchtlich. Begriffe wie Factory, Iterator oder Singleton werden in OOP
-Projekten routinemäßig verwendet und sollten für jeden betroffenen Entwickler dieselbe Bedeutung haben.
Wir wollen nachfolgend einige der wichtigsten Design-Patterns vorstellen und ihre Implementierung in Java skizzieren. Die
Ausführungen sollten allerdings nur als erster Einstieg in das Thema angesehen werden. Viele Patterns können hier aus
Platzgründen gar nicht erwähnt werden, obwohl sie in der Praxis einen hohen Stellenwert haben (z.B. Adapter, Bridge,
Mediator, Command etc.). Zudem ist die Bedeutung eines Patterns für den OOP-Anfänger oft gar nicht verständlich, sondern
erschließt sich erst nach Monaten oder Jahren zusätzlicher Programmiererfahrung.
Die folgenden Abschnitte ersetzen also nicht die Lektüre weiterführender Literatur zu diesem Thema. Das oben erwähnte Werk
von Gamma et al. ist nach wie vor einer der Klassiker schlechthin (die Autoren und ihr Buch werden meist als "GoF"
bezeichnet, ein Akronym für "Gang of Four"). Daneben existieren auch spezifische Kataloge, in denen die Design-Patterns zu
bestimmten Anwendungsgebieten oder auf der Basis einer ganz bestimmten Sprache, wie etwa C++ oder Java, beschrieben
werden.
69
Composite-Muster In der Programmierpraxis werden häufig Datenstrukturen benötigt, bei denen die einzelnen Objekte zu Baumstrukturen
zusammengesetzt werden können.
Es gibt viele Beispiele für derartige Strukturen:
l Die Menüs in einem Programm enthalten Menüpunkte und Untermenüs. Untermenüs enthalten weitere Menüpunkte,
sind aber selbst Menüpunkte im übergeordneten Menü.
l Ein Verzeichnis in einem Dateisystem enthält Dateien und Unterverzeichnisse. Unterverzeichnisse weisen dieselbe
prinzipielle Struktur wie ihre übergeordneten Verzeichnisse auf. Sowohl Dateien als auch Unterverzeichnisse haben
gemeinsame Eigenschaften, wie etwa einen Namen oder zugeordnete Rechte.
l Die Komponenten einer grafischen Oberfläche können sowohl einfache Dialogelemente (Buttons, Textfelder,
Listboxen) als auch Container (Unterfenster, Split-Panels, Tab-Panels) sein. Container enthalten ebenfalls
Komponenten (vergleiche zum Beispiel die Hierarchie der AWT-Fensterklassen).
l Ein mechanisches Bauteil besteht aus elementaren Teilen, die nicht mehr weiter zerlegt werden können, und
zusammengesetzten Bauteilen, die aus Unterbauteilen bestehen.
Für diese häufig anzutreffende Abstraktion gibt es ein Design-Pattern, das als Composite bezeichnet wird. Es ermöglicht
derartige Kompositionen und erlaubt eine einheitliche Handhabung von individuellen und zusammengesetzten Objekten. Ein
Composite enthält folgende Bestandteile:
l Eine (oft abstrakte) Basisklasse, die sowohl zusammengesetzte als auch elementare Objekte repräsentiert. Diese
Basisklasse wird auch als "Component" bezeichnet.
l Alle elementaren Objekte sind aus dieser Basisklasse abgeleitet.
l Daraus abgeleitet gibt es mindestens eine Containerklasse, die in der Lage ist, eine Menge von Objekten der
Basisklasse aufzunehmen.
Somit sind beide Bedingungen erfüllt. Der Container ermöglicht die Komposition der Objekte zu Baumstrukturen, und die
Basisklasse stellt die einheitliche Schnittstelle für elementare Objekte und Container zur Verfügung.
Das Klassendiagramm für ein Composite sieht so aus:
Klassendiagramm eines Composite
Das folgende Listing skizziert dieses Design-Pattern am Beispiel einer einfachen Menüstruktur:
001 /* Listing1013.java */
002
003 class MenuEntry1
004 {
005 protected String name;
006
007 public MenuEntry1(String name)
008 {
009 this.name = name;
010 }
011
012 public String toString()
013 {
014 return name;
015 }
016 }
017
AbstractComponent
ConcreteComponent 1
ConcreteComponent 2
Container
70
018 class IconizedMenuEntry1 extends MenuEntry1
020 {
021 private String iconName;
022
023 public IconizedMenuEntry1(String name, String iconName){
025 super(name);
026 this.iconName = iconName;
027 }
028 }
029
030 class CheckableMenuEntry1 extends MenuEntry1
032 {
033 private boolean checked;
034
035 public CheckableMenuEntry1(String name, boolean checked) {
037 super(name);
038 this.checked = checked;
039 }
040 }
041
042 class Menu1 extends MenuEntry1
044 {
045 MenuEntry1[] entries;
046 int entryCnt;
047
048 public Menu1(String name, int maxElements) {
050 super(name);
051 this.entries = new MenuEntry1[maxElements];
052 entryCnt = 0;
053 }
054
055 public void add(MenuEntry1 entry) {
057 entries[entryCnt++] = entry;
058 }
059
060 public String toString()
061 {
062 String ret = "(";
063 for (int i = 0; i < entryCnt; ++i) {
064 ret += (i != 0 ? ",": "") + entries[i].toString();
065 }
066 return ret + ")";
067 }
068 }
069
070 public class Listing1013
071 {
072 public static void main(String[] args)
073 {
074 Menu1 filemenu = new Menu1("Datei", 5);
075 filemenu.add(new MenuEntry1("Neu"));
076 filemenu.add(new MenuEntry1("Laden"));
077 filemenu.add(new MenuEntry1("Speichern"));
078
079 Menu1 confmenu = new Menu1("Konfiguration", 3);
080 confmenu.add(new MenuEntry1("Farben"));
081 confmenu.add(new MenuEntry1("Fenster"));
082 confmenu.add(new MenuEntry1("Pfade"));
083 filemenu.add(confmenu);
084
085 filemenu.add(new MenuEntry1("Beenden"));
086
087 System.out.println(filemenu.toString());
088 }
089 }
Listing 10.13: Das Composite-Pattern
71
Die Komponentenklasse hat den Namen MenuEntry1. Sie repräsentiert Menüeinträge und ist Vaterklasse der
spezialisierten Menüeinträge IconizedMenuEntry1 und CheckableMenuEntry1. Zudem ist sie Vaterklasse des
Containers Menu1, der Menüeinträge aufnehmen kann.
Bestandteil der gemeinsamen Schnittstelle ist die Methode toString. In der Basisklasse und den elementaren Menüeinträgen
liefert sie lediglich den Namen des Objekts. In der Containerklasse wird sie überlagert und liefert eine geklammerte Liste aller
darin enthaltener Menüeinträge. Dabei arbeitet sie unabhängig davon, ob es sich bei dem jeweiligen Eintrag um einen
elementaren oder einen zusammengesetzten Eintrag handelt, denn es wird lediglich die immer verfügbare Methode toString
aufgerufen.
Das Testprogramm erzeugt ein "Datei"-Menü mit einigen Elementareinträgen und einem Untermenü "Konfiguration" und gibt
es auf Standardausgabe aus: (Neu,Laden,Speichern,(Farben,Fenster,Pfade),Beenden)
72
Observer-Muster Bei der objektorientierten Programmierung werden Programme in viele kleine Bestandteile zerlegt, die für sich genommen
autonom arbeiten. Mit zunehmender Anzahl von Bausteinen steigt allerdings der Kommunikationsbedarf zwischen diesen
Objekten, und der Aufwand, sie konsistent zu halten, wächst an. Ein Observer ist ein Design-Pattern, das eine Beziehung
zwischen einem Subject und seinen Beobachtern aufbaut. Als Subjectwird dabei ein Objekt bezeichnet, dessen Zustands-
änderung für andere Objekte interessant ist. Als Beobachter werden die Objekte bezeichnet, die von Zustandsänderungen des
Subjekts abhängig sind; deren Zustand also dem Zustand des Subjekts konsistent folgen muß.
Kurzbeschreibung Ermöglicht die dynamische Registrierung von Objektabhängigkeiten, so dass bei einem Zustandswechsel eines
Objekts alle von ihm abhängigen Objekte benachrichtigt werden.
Problembeschreibung
In vielen Anwendungsbereichen soll sich der Zustandswechsel eines Objekts direkt auf den Zustand bzw. das Verhalten
anderer Objekte auswirken.
Beispiel : Ein Datenbestand und seine – u.U. gleichzeitige – Darstellung in verschiedenen Formaten in einem GUI-System
(z. B. Tabelle, Balkendiagramm, Tortendiagramm). Jede Änderung des Datenbestandes muss sich umgehend auf alle Dar-
stellungen auswirken.
Eine enge Kopplung der beteiligten Objekte ( die beteiligten Objekte haben voneinander Kenntnis) ist meist nicht
wünschenswert, da dadurch die unabhängige Verwendung und Modifikation ihrer jeweiligen Klassen stark eingeschränkt
wird. Außerdem müssen in diesem Fall die Abhängigkeiten bereits zur Compilezeit bekannt sein, was eine flexible
dynamische Anpassung zur Laufzeit verhindert.
Problemlösung Bei dem Objekt, von dessen Zustand andere Objekte abhängen (Publisher-Objekt), wird eine Liste der abhängigen
Objekte geführt. In diese Liste tragen sich alle Objekte, die über den Zustand dieses Objekts auf dem Laufenden gehalten
werden wollen (weil sie von ihm abhängen), ein (Subscriber-Objekte, Observer-Objekte).
Bei einem Wechsel seines Zustands informiert das Publisher-Objekt alle eingetragenen Observer-Objekt hierüber (notify).
Diese können dann den neuen Zustand vom Publisher-Objekt ermitteln und entsprechend der eingetretenen Änderung
reagieren (z.B. ihren eigenen Zustand an den Zustand des Publisher-Objektes anpassen).
Die Anzahl der Observer-Objekte muss dem Publisher-Objekt a priori nicht bekannt sein. Bei ihm können sich zur
Laufzeit beliebig viele Observer-Objekte an- bzw. auch wieder abmelden.
Publisher-Objekt und Observer-Objekte sind von einander entkoppelt und können unabhängig voneinander modifiziert
werden.
Die Publisher-Schnittstelle wird durch eine geeignete Klasse (Publisher) zur Verfügung gestellt. Diese Klasse dient als
Basisklasse für konkrete Publisher-Klassen (ConcretePublisher), die die Datenkomponenten für den jeweiligen
Zustand und die Methoden zum Setzen und Ermitteln derselben bereitstellen.
Das Interface zum Informieren von Observer-Objekten wird durch eine abstrakte Klasse (Observer) definiert
Dieses Interface wird von konkreten Observer-Klassen (ConcreteObserver) implementiert. Objekte dieser Klassen
enthalten – neben ihren eigentlichen Zustands-Datenkomponenten – eine Referenz auf das konkrete Publisher-Objekt, bei
dem sie sich eingetragen haben.
Abbildung 10.8: Klassendiagramm eines Observers
Publisher
-observers:Observer
+attach:Observer +detach:Observer +notify:void
publisher
1
0..n observers
interface Observer
+update:void
ConcreteObserver
-observState:State -publisher:ConcretePublisher
+update:void
ConcretePublisher
-subjState:State
+setState:void +getState:State
void notify()
{ for all o
in observers
o.update();
}
73
Anwendungskonsequenzen
▻ Publisher und Observer können unabhängig voneinander geändert und ausgetauscht werden.
Publisher können wiederbenutzt werden, ohne ihre Observer wiederzubenutzen und umgekehrt.
Observer können hinzugefügt werden, ohne den Publisher oder andere Observer zu verändern.
▻ Die Kopplung zwischen Publisher und Observer ist abstrakt und minimal.
Ein Publisher-Objekt weiß lediglich, dass es eine Liste von Observer-Objekten besitzt, die das Observer-Interface
implementieren. Es kennt nicht die konkrete Klasse seiner Observer.
Publisher und Observer können unterschiedlichen Abstraktions-Ebenen (Schichtenmodell !) angehören.
▻ Observer-Objekte können gegebenenfalls selbst auch einen Zustandswechsel beim Publisher-Objekt bewirken
▻ Die Information über den Zustandswechsel (Notifikation) durch das Publisher-Objekt ist automatisch eine Broadcast-
Kommunikation. Es werden immer alle eingetragenen Observer-Objekte informiert, unabhängig davon, wieviel es sind.
Es obliegt einem Observer-Objekt, eine Notifikation gegebenenfalls zu ignorieren.
▻ Falls sehr viele Observer-Objekte eingetragen sind, kann eine Notifikation und der dadurch ausgelöste Observer-Update
u.U. eine längere Zeit dauern.
▻ Da das eine Zustandsänderung bewirkende Objekt keine Information über die Observer und die mit diesen verbundenen
"Update"-Kosten hat, können "leichtfertige" Zustandsänderungen einen erheblichen zeit- und damit kostenintensiven
Aufwand bewirken.
▻ Das einfache Notifikations-Protokoll liefert keine Informationen darüber, was sich im Publisher-Objekt geändert
hat. Dies festzustellen, obliegt dem Observer-Objekt, was den Update-Aufwand gegebenenfalls noch erhöht.
Als Alternative kann u.U. ein erweitertes Protokoll definiert werden, dass detailliertere Zustandsänderungs-Info liefert.
▻ Es gibt Fälle, bei denen sinnvoll ist, dass sich ein Observer-Objekt bei mehreren Publisher-Objekten für eine
Notifikation einträgt. In diesen Fällen muss die Update-Botschaft eine Information über das absendende Publisher-
Objekt enthalten
74
Das folgende Listing zeigt eine beispielhafte Implementierung: 001 /* Listing1015.java */
002 package observer;
003 interface Observer
004 {
005 public void update(Subject subject);
006 }
007
008 class Subject //Publisher
009 {
010 Observer[] observers = new Observer[5];
011 int observerCnt = 0;
012
013 public void attach(Observer observer)
014 {
015 observers[observerCnt++] = observer;
016 }
017
018 public void detach(Observer observer)
019 {
020 for (int i = 0; i < observerCnt; ++i) {
021 if (observers[i] == observer) {
022 --observerCnt;
023 for (;i < observerCnt; ++i) {
024 observers[i] = observers[i + 1];
025 }
026 break;
027 }
028 }
029 }
030
031 public void fireUpdate()
032 {
033 for (int i = 0; i < observerCnt; ++i) {
034 observers[i].update(this);
035 }
036 }
037 }
//Concrete Publisher (Subject)
class Counter extends Subject{
int cnt = 0;
public void inc() {
++cnt;
fireUpdate();
}
}
//class Listing1015 ist Applikationsklasse und konkreter Observer durch Implementierung des Interfaces
//Observer als anonyme Klasse public class Listing1015
{
public static void main(String[] args)
{
Counter counter = new Counter();
counter.attach( new Observer() {
public void update(Subject subject){
System.out.println("divisible by 3: ");
}
});
while (counter.cnt < 10) {
counter.inc();
System.out.println(counter.cnt);
}
}
}
Listing: Das Observer-Pattern
75
Als konkreter Publisher wird hier die Klasse Counter verwendet. Sie erhöht bei jedem Aufruf von inc den eingebauten
Zähler um eins und informiert alle registrierten Beobachter, falls der neue Zählerstand durch drei teilbar ist. Im Hauptprogramm
instanzieren wir ein Counter-Objekt und registrieren eine lokale anonyme Klasse als Listener, die bei jeder Benachrichtigung
eine Meldung ausgibt. Während des anschließenden Zählerlaufs von 1 bis 10 wird sie dreimal aufgerufen: 1
2
divisible by 3: 3
4
5
divisible by 3: 6
7
8
divisible by 3: 9
10
Das Observer-Pattern ist in Java sehr verbreitet, denn die Kommunikation zwischen graphischen Dialogelementen
und ihrer Anwendung basiert vollständig auf dieser Idee. Allerdings wurde es etwas erweitert, die Beobachter
werden als Listener bezeichnet, und es gibt von ihnen eine Vielzahl unterschiedlicher Typen mit unterschiedlichen
Aufgaben. Da es zudem üblich ist, daß ein Listener sich bei mehr als einem Subjekt registriert, wird ein Aufruf von
update statt des einfachen Arguments jeweils ein Listener-spezifisches Ereignisobjekt übergeben. Darin werden
neben dem Subjekt weitere spezifische Informationen untergebracht. Zudem haben die Methoden gegenüber der
ursprünglichen Definition eine andere Namensstruktur, und es kann sein, daß ein Listener nicht nur eine, sonderen
mehrere unterschiedliche Update-Methoden zur Verfügung stellen muß, um auf unterschiedliche Ereignistypen zu
reagieren. Das Listener-Konzept von Java wird auch als Delegation Based Event Handling bezeichnet.
Hinweis