Holger Röder Java: Kapitel 7 Grafische ... · PDF fileHolger Röder Java: Kapitel 7...

47
se Programmentwicklung Winter 2008/2009 © Holger Röder Java: Kapitel 7 Grafische Benutzungsschnittstellen (GUIs) mit Swing Programmentwicklung WS 2008/2009 Holger Röder [email protected]

Transcript of Holger Röder Java: Kapitel 7 Grafische ... · PDF fileHolger Röder Java: Kapitel 7...

se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Java: Kapitel 7

Grafische Benutzungsschnittstellen (GUIs) mit Swing

Programmentwicklung WS 2008/2009

Holger Röder [email protected]

2se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Überblick über Kapitel 7

Die GUI-Bibliotheken in Java: AWT und SwingBeispiel: einfache Swing-AnwendungSwing

Komponenten, Container, FensterEreignisbehandlungMenüs und ToolbarsGUI-KomponentenModel-Delegate-PrinzipSwing und Threads

3se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

AWT

Die im JDK enthaltene Grafikbibliothek Abstract Windowing Toolkit(AWT) ermöglicht seit Java 1.0 die Erstellung grafischer Oberflächen für Java-Programme.AWT ist leicht verständlich, bringt jedoch einige Nachteile mit sich:

AWT nutzt die GUI-Elemente des Betriebssystems – somit kein einheitliches „Look-and-Feel“ von Java-Programmen unter verschiedenen Betriebssystemen.Nur eine eingeschränkte Menge von GUI-Elementen steht zur Verfügung (z. B. keine Tabellen, keine Bäume).

4se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Swing

Seit Java 1.2 steht mit Swing eine Alternative zum AWT zur Verfügung.Swing „zeichnet“ die GUI-Komponenten selbst: Swing-Programme sehen somit auf allen Plattformen (weitgehend) gleich aus. Dies ermöglicht es auch, das Look-and-Feel eines Swing-Programms zur Laufzeit umzuschalten (pluggable look and feel).Swing verwendet eine Model-Delegate-Architektur zur Trennung von Verarbeitungs- und Präsentationslogik.Der ursprüngliche Performance-Nachteil von Swing- gegenüber AWT-Anwendungen spielt heute praktisch keine Rolle mehr.Swing erweitert in vielen Fällen die AWT-Klassen.

5se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Ein einfacher Beispiel-Dialog

Fenster(JFrame)

Textfelder(JTextField)

Labels(JLabel)

Button(JButton)

6se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Swing-Beispiel (1)

public class BeispielDialog extends JFrame {JButton buttonSpiegeln = new JButton();JLabel label1 = new JLabel();JLabel label2 = new JLabel();JTextField feldEingabe = new JTextField();JTextField feldAusgabe = new JTextField();...

}

Eigene Fensterklasseabgeleitet von JFrame

Je GUI-Element einAttribut

7se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Swing-Beispiel (2)

...public BeispielDialog() {

super("Beispiel-Dialog");setLayout(null);

label1.setText("Eingabe:");label1.setBounds(new Rectangle(20, 20, 100, 30));add(label1);...

}...

Konstruktor

Eigenschaften der GUI-Komponenten werdengesetzt

Komponente wird zumFenster hinzugefügt

Aufruf des Oberklassenkonstruktors setzt Fenstertitel

8se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Swing-Beispiel (3)

public static void main(String[] args) {SwingUtilities.invokeLater(new Runnable() {

public void run() {BeispielDialog dialog = new BeispielDialog();dialog.pack();dialog.setSize(400, 150);dialog.setLocation(300, 200);dialog.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);dialog.setVisible(true);}

});}...

Ein Objekt der von JFrame abgeleitetenKlasse wird instanziiert …

... und “sichtbar” gemacht

Um Thread-Sicherheit zu gewährleisten, erfolgt die Initialisierung des Fensters in einem separaten Thread

9se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Swing-Beispiel (4) – Look-and-Feel

UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");

SwingUtilities.updateComponentTreeUI(this);

UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");

SwingUtilities.updateComponentTreeUI(this);

// Vor JFrame-Instanziierung:JFrame.setDefaultLookAndFeelDecorated(true);...UIManager.setLookAndFeel(

"javax.swing.plaf.metal.MetalLookAndFeel");SwingUtilities.updateComponentTreeUI(this);

10se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Komponenten und Container

Als Komponenten werden in Swing einzelne GUI-Elemente bezeichnet, die über eine bestimmte Art der Darstellung verfügen und auf Ereignisse reagieren können.

Beispiele: Buttons (JButton), Eingabefelder (JTextField), Labels (JLabel), Tabellen (JTable) – Basisklasse JComponent

Container sind spezielle Komponenten, die ihrerseits weitere Komponenten aufnehmen können. Der Container ermöglicht das Hinzufügen und Entfernen von Komponenten und übernimmt die Positionierung der in ihm enthaltenen Komponenten.

Beispiele: Panels (JPanel) , Toolbars (JToolBar), Scroll-Container (JScrollPane)

Schachtelung: JTextFieldinnerhalb eines JScrollPane-Containers

11se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Top-Level-Container

Top-Level-Container sind Container auf oberster EbeneJFrame: Hauptfenster einer Anwendung, typisch mit Rahmen, Systemmenü, Titelleiste, MenüleisteJDialog: zumeist modale Dialogfenster (für Benutzerabfragen, spezifische Programmmeldungen etc.)JWindow: rahmenlose Fenster ohne Menüleiste

Die meisten Swing-Anwendungen basieren auf JFrame als Basisklasse für das Hauptfenster der Anwendung.

12se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

JFrame – Schematischer Aufbau

Frame (JFrame)Root Pane

Layered PaneMenü/Content P.

Glass Pane

Die Content Paneenthält die GUI-Komponenten (Buttons, Eingabefelder etc.)

Die LayeredPane enthält (optional) eine Menüleiste und die Content Pane

Datei Bearbeiten Ansicht

Hallo Welt OK

Die Glass Pane ist üblicherweise „unsichtbar“ und kann Oberflächenereignisse filtern

13se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

JFrame als Basis für eigene Anwendungen

Über die Methode add() können GUI-Komponenten zur Content Pane des Hauptfensters hinzugefügt werden.

Häufig verwendete Methoden:setTitle(String) – setzt den FenstertitelsetMenuBar(MenuBar) – fügt eine Menüleiste hinzupack() – setzt alle Komponenten auf ihre „bevorzugte“ GrößesetSize(int, int) – setzt FenstergrößesetVisible(boolean) – zeigt oder versteckt das Fensterdispose() – gibt Ressourcen frei, schließt das FenstersetDefaultCloseOperation(int) – Verhalten beim Schließen des Fensters (JFrame.EXIT_ON_CLOSE beendet das Programm beim Schließen des Fensters

JButton meinButton = new JButton();...add(meinButton); // Button wird platziert

14se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Layout-Manager

Die pixelgenaue Positierung von GUI-Komponenten bringt Nachteile mit sich: bei Größenänderung des Fensters, bei unterschiedlichen Schriftgrößen etc. werden die GUI-Komponenten evtl. nicht korrekt dargestellt.Aus diesem Grund übernimmt in Swing ein Layout-Manager die Positionierung der Komponenten innerhalb eines Containers. Verschiedene Layout-Manager sind verfügbar, z. B.

FlowLayout: Anordnung nebeneinander in Zeile, evtl. neue ZeileBorderLayout: Anordnung links/rechts/oben/unten und mittigGridLayout: Anordnung in rechteckigem Gitter, alle Zellen haben die gleiche GrößeGridBagLayout: ebenfalls Gitteranordnung, Zellen können unterschiedliche Größe haben, Komponenten können sich über mehrere Zellen erstreckenSonderfall null: kein LayoutManager, pixelgenaue Positionierung

Über die Methode setLayout() des Containers kann das entsprechende Layout eingestellt werden.

15se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Layout-Manager – Vergleich

// Layout-Manager setzen...add(new JButton("Button 1"), BorderLayout.EAST);add(new JButton("Button 2"), BorderLayout.SOUTH);add(new JButton("Button 3"), BorderLayout.WEST);add(new JButton("Button 4"), BorderLayout.CENTER);add(new JButton("Button 5"), BorderLayout.NORTH);

setLayout(new FlowLayout())

setLayout(new BorderLayout())

setLayout(new GridLayout(3, 2))

Zweiter Parameter nurfür BorderLayout

16se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Ereignisbehandlung

Die Ereignisbehandlung innerhalb von Swing-Anwendungen erfolgt nach dem „Listener-Prinzip“:

Listener-Objekte (event listener) registrieren sich bei möglichen Ereignisquellen (event sources, z. B. Buttons, Textfelder)Bei Auftreten eines Ereignisses (Mausklick, Tastatureingabe etc.) werden die registrierten Listener-Objekte benachrichtigt.Die Listener-Objekte initiieren die passende „Reaktion“auf das Ereignis.

Listener können sich bei beliebig vielen Ereignisquellen registrieren, ebenso können Quellen über beliebig viele registrierte Listenerverfügen.

17se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Ereignisbehandlung nach dem Listener-Prinzip

“Listener-Objekt”

Das Listener-Objekt registriert sich beim Button und wird bei Ereignissen benachrichtigt

Ereignisse: Mausklick, Tastatureingabe ...

Tritt ein Ereignis ein, kann das Listener-Objekt z. B. eine Methode des JFrame-Unterklassenobjekts aufrufen

buttonSpiegeln.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {

buttonSpiegeln_actionPerformed(e);}

});...private void buttonSpiegeln_actionPerformed(ActionEvent e) {

StringBuffer eingabe = new StringBuffer(feldEingabe.getText());eingabe.reverse();feldAusgabe.setText(eingabe.toString());

}

Anonymes Listener-Objekt

Ereignisbehandlung

18se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Ereignisse und Listener-Schnittstellen

Swing kennt verschiedene Arten von Ereignissen, die jeweils durch unterschiedliche Ereignisklassen repräsentiert werden. Listener-Objekte, die über entsprechende Ereignisse benachrichtigt werden, müssen die jeweilige Schnittstelle implementieren.

Die Registrierung der Listener-Objekte erfolgt über entsprechende Registrierungsmethoden, z. B. addMouseMotionListener()

Ereignisklasse Beschreibung Listener-Schnittstelle

KeyEvent Tastendruck KeyListener

MouseEvent Mausklick, Betreten/ Verlassen der Komp.

MouseListener

MouseMotionEvent Mausbewegung MouseMotionListener

WindowEvent Fenster geschlossen, verkleinert…

WindowListener

ActionEvent Aktion ausgelöst (z.B. Button gedrückt)

ActionListener

19se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Menüs

Eine Menüleiste ist ein Objekt vom Typ JMenuBar, das dem Hauptfenster über die Methode addJMenuBar() hinzugefügt wird.Die Menüs sind Instanzen von JMenu, die einzelnen Menüeinträge Instanzen von JMenuItem.JMenu ist eine Unterklasse von JMenuItem: Untermenüs können somit realisiert werden, indem ein JMenu-Objekt anstelle eines JMenuItem-Objekts zu einem Menü hinzugefügt wird.

JMenuBar menueleiste = new JMenuBar();JMenu menueDatei = new JMenu();JMenu menueBearbeiten = new JMenu();JMenuItem menueEintragSpiegeln = new JMenuItem();

20se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Menüs (2)

menueDatei.setText("Datei");menueBearbeiten.setText("Bearbeiten");

menueEintragSpiegeln.setText("Spiegeln");menueEintragSpiegeln.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {menueEintragSpiegeln_actionPerformed(e);

}});

menueBearbeiten.add(menueEintragSpiegeln);

menueleiste.add(menueDatei);menueleiste.add(menueBearbeiten);

setJMenuBar(menueleiste);

Anonymes Listener-Objekt

Menüeintrag zu Menü hinzufügen

Menü zu Menüleiste hinzufügen

Menüleiste zu Fenster hinzufügen

21se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Toolbars

Toolbars (Werkzeugleisten) sind Container, die andere Komponenten (z. B. Buttons) neben- oder untereinander gruppieren.Toolbars werden als Objekte vom Typ JToolBar realisiert.

JToolBar toolbar = new JToolBar();JButton toolbarButtonSpiegeln =

new JButton("Text spiegeln", new ImageIcon("icon.gif"));

22se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Toolbars (2)

JToolBar toolbar = new JToolBar();

JButton toolbarButtonSpiegeln = new JButton("Text spiegeln", new ImageIcon("icon.gif"));

toolbarButtonSpiegeln.addActionListener(new ActionListener() { ...});

toolbar.add(toolbarButtonSpiegeln);

add(toolbar, BorderLayout.NORTH);Inhalte (Komponenten) zurToolbar hinzufügen

Toolbar zum Fenster hinzufügen

Toolbars können standardmäßig vom Benutzer frei an den vier Fensterrändern verankert oder „freischwebend“ positioniert werden.Hierzu muss das Fenster BorderLayout verwenden. Die Toolbarmuss am Rand angeordnet werden (z. B. BorderLayout.NORTH), die übrigen Fensterinhalte (innerhalb eines Containers) in der Mitte (BorderLayout.CENTER).

23se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Funktionalität zusammenfassen: Actions

Häufig soll in Swing-Anwendungen die gleiche Aktion auf verschiedenen Wegen (Menü, Toolbar etc.) ausführbar sein.Actions erlauben es, die gleiche Funktionalität verschiedenen Komponenten zu hinterlegen, ohne die Funktionalität mehrfach (z. B. als anonyme ActionListener-Objekte) implementieren zu müssen. Die Action verwaltet zentral den Zustand (Text, Icon, Ausgewählt? etc.) für die Komponenten.

Gleiche Action hinterlegt: Beschriftungstext und hinterlegteFunktionalität sind einheitlich

setEnabled(false) im Action-Objekt: alle Komponenten, die mit der Actionverknüpft sind, werden deaktiviert

24se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Action-Beispiel

Die Schnittstelle Action implementiert die Schnittstelle ActionListener und kann für alle Komponenten eingesetzt werden, die Action-Events auslösen: Menüs, Buttons, Textfelder etc.Die Klasse AbstractAction bietet Standardimplementierungen für die in Action definierten Methoden und eignet sich in vielen Fällen als Basisklasse für eigene Actions.

class SpiegelnAction extends AbstractAction {public SpiegelnAction(String text, Icon icon) {

super(text, icon);}public void actionPerformed(ActionEvent e) {

StringBuffer eingabe = new StringBuffer(feldEingabe.getText());eingabe.reverse();feldAusgabe.setText(eingabe.toString());

}}

Eigene Action-Implementierung

Oberklassenkonstruktor: setztBeschriftungstext und Icon

Methode wird aufgerufen, wenn einAction-Event ausgelöst wurde

25se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

final SpiegelnAction spiegelnAction = new SpiegelnAction("Text spiegeln", new ImageIcon("icon.gif"));

buttonSpiegeln = new JButton(spiegelnAction);add(buttonSpiegeln);...menueEintragSpiegeln = new JMenuItem();menueEintragSpiegeln.setAction(spiegelnAction);menueEintragSpiegeln.setIcon(null);menueBearbeiten.add(menueEintragSpiegeln);...toolbarButtonSpiegeln = new JButton(spiegelnAction);toolbar.add(toolbarButtonSpiegeln);

Action-Beispiel (2)Action instanziieren

Action den verschiedenenKomponenten zuweisen(Konstruktor, expliziteZuweisung)

26se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Zustand in Actions

Actions können verschiedene Zustandsattribute verwalten. Über die Methode putValue(String schluessel, Object o) kann ein Attribut gesetzt werden, getValue(String schluessel) liefert das Attribut zurück.

putValue(SMALL_ICON, new ImageIcon("ende.gif"));

Schlüssel Beschreibung Angewendet auf

ACCELERATOR_KEY Tastenkombination Menü-EinträgeNAME Beschriftung Buttons, Checkboxen,

Radiobuttons, Menü-Einträge

SHORT_DESCRIPTION ToolTip-Text Buttons, Checkboxen, Radiobuttons

SMALL_ICON Icon Buttons, Menü-Einträge

… (siehe http://java.sun.com/javase/6/docs/api/javax/swing/Action.html)

27se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Meldungen mit JOptionPane

JOptionPane bietet statische Methoden zur Anzeige typischer modaler Programmmeldungen (Meldung, Nachfragen etc.)

JOptionPane.showMessageDialog(null, "Text wurde gespiegelt", "Meldung", JOptionPane.INFORMATION_MESSAGE);

if (JOptionPane.showConfirmDialog(null, "Soll der Text gespiegelt werden?", "Frage", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {

...}

28se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Übersicht: Swing-GUI-Komponenten (Auszug)

javax.swing.JComponent

AbstractButton

JMenuItem

JToggleButton

JButton

JRadioButton

JCheckBox

JTextComponent

JEditorPane

JTextField

JLabel

JToolTip

JPanel

JMenu

JOptionPane

JScrollPane

JTabbedPaneJTextArea

JTable

JTree

29se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

JPanel

Ein JPanel-Objekt ist ein (meist) unsichtbarer Container, der in andere Container eingebettet wird.Jedes JPanel-Objekt verfügt über einen Layout-Manager (Standard: FlowLayout), der die enthaltenen Komponenten anordnet.Komplexe Dialoge bestehen häufig aus geschachtelten JPanel-Containern.

JFrame mit Layout-Manager GridLayout(2, 1)

JPanel mit Layout-Manager FlowLayout()

JPanel mit Layout-Manager BorderLayout()

30se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

JTabbedPane

Mehrere Registerkarten (Tabs) in einem Fenster können mit der Klasse JTabbedPane dargestellt werden.Jede Registerkarte (typisch JPanel-Objekte) kann eigene GUI-Komponenten beinhalten. Über eine am Rand liegende Registerleiste kann zwischen den einzelnen Registerkarten umgeschaltet werden.

JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);

JPanel tab1 = new JPanel();tab1.add(new JLabel("Eingabe auf Registerkarte 1"));tab1.add(new JTextField(10));tab1.add(new JButton("Auswerten"));JPanel tab2 = new JPanel();...tabbedPane.addTab("Eins", tab1);tabbedPane.addTab("Zwei", tab2);add(tabbedPane);

Überladener Konstruktor von JTabbedPane: Registerleiste oben positionieren, ggf. scrollen

Für jede Registerkarte eineigenes JPanel-Objekterzeugen und “füllen”

Registerkarten hinzufügen

31se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

JLabel, JTextField

Für Beschriftungen (optional mit Icon) können JLabel-Komponentenverwendet werden.

JTextField stellt ein einfaches Eingabefeld dar:

Zur Eingabe von Passwörtern existiert mit JPasswordField eine Spezialisierung von JTextField.

JLabel label = new JLabel("Label mit Icon", new ImageIcon("icon.jpg"), SwingConstants.RIGHT);

Icon als .jpg

JTextField text = new JTextField("Hier steht Text.");...String s = text.getText();

Text des Textfelds auslesen

32se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

JButton, JCheckBox

Die Klasse JButton stellt mit Text oder einem Icon beschriftete Buttons dar.

JCheckBox repräsentiert Checkboxen.

JButton button = new JButton("Drück mich!", new ImageIcon("C:/pe/icon.gif"));

button.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {

... // Ereignisbehandlung});

Ereignisbehandlung nach dem Listener-Prinzip: anonymes Listener-Objekt registriert sich beim Button

JCheckBox checkbox1 = new JCheckBox("Auswahlbox");JCheckBox checkbox2 = new JCheckBox("Auswahlbox“, true);...if (checkbox1.isSelected()) {

checkbox2.setSelected(false);}

Auswahl abfragen, Auswahl setzen

33se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

JRadioButton

JRadioButton ähnelt JCheckBox und stellt Radiobuttons dar.Mehrere Radiobuttons können zu einer ButtonGroup gruppiert werden: in einer Gruppe kann stets nur ein Radiobutton aktiv sein.

JRadioButton button1 = new JRadioButton("Möglichkeit 1", true);JRadioButton button2 = new JRadioButton("Möglichkeit 2");JRadioButton button3 = new JRadioButton("Möglichkeit 3");

add(button1);add(button2);add(button3);

ButtonGroup group = new ButtonGroup();group.add(button1);group.add(button2);group.add(button3); Logische Gruppierung der Radiobuttons

34se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Trennung von Daten und Darstellung

Die architektonische Trennung der Daten (und Verarbeitungslogik) von der Darstellung der Daten ist ein bewährtes Prinzip des objekt-orientierten Software-Entwurfs:

Saubere Strukturierung des Programmcodes, Entkopplungleichtere Wartung/Erweiterung

Darstellung der(selben) Daten auf verschiedene Arten

Auch in Swing-Anwendungen werden Daten und Darstellung getrennt.

a=30%b=50%c=20%

30%

50%

20%

Daten

Darstellung 1

Darstellung 2

35se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Model-View-Controller (MVC)

MVC ist ein Architekturmuster, bei dem Daten (Model), Darstellung (View) und Steuerung (Controller) getrennt werden.

Model View

Controller

Daten und Verarbeitungs-

logik

informiert über notwendige Darstellungsänderung (z. B. durch Textselektion)

(Grafische) Darstellung

ruft Verarbeitungs-logik auf, leitet Änderungen weiter

Events(z. B. Benutzereingabe)

fragt Daten ab

benachrichtigt registrierte Views(Listener) bei Änderungen

a=30%b=50%c=20%

36se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

MVC in Swing: Model-Delegate-Prinzip

Bei Swing kommt eine vereinfachte Variante von MVC zum Einsatz: das Model-Delegate-Prinzip.Jede Swing-Komponente gliedert sich in zwei Bestandteile:

Model: Daten (Zustand) der KomponenteUI-Delegate: Grafische Darstellung und Steuerung der Komponente (Darstellung der Daten und Reaktion auf Ereignisse)

Kombination von View und Controller

Model View

Controller

Delegate

37se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Model und Delegate bei Swing-Komponenten

Bei einfachen Komponenten (Textfelder, Buttons etc.) ist die Aufteilung kaum sichtbar:

Das Modell wird durch Aufruf der Komponentenmethode verändert.Bei UI-Ereignissen (Eintippen/Einfügen von Text) wird das Modell automatisch entsprechend geändert und die Darstellung aktualisiert.

Bei Komponenten mit komplexen Inhalten (Listen, Tabellen etc.) wird die Separierung von Model und UI-Delegate klar erkennbar.Zu allen Swing-GUI-Komponenten existieren passende Schnittstellen, die die Implementierung eigener Modellklassen erlauben. Häufig enthält das JDK auch Standard-Implementierungen dieser Schnittstellen.

JTextField feldEingabe = new JTextField();feldEingabe.setText("Hallo Welt");

GUI-Komponente Model Interface Standard-Impl.

JButton ButtonModel DefaultButtonModel

PlainDocument …

DefaultTableModel

JTextArea Document

JTable TableModel

etc.

38se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

JList

Für Listen steht die Klasse JList zur Verfügung.Der Inhalt der Liste (Listenmodell) kann in einem Objekt vom TypDefaultListModel verwaltet werden. Der Zugriff erfolgt wie bei Vector. Bei Änderungen benachrichtigt das Listenmodell die ListBoxautomatisch, die Darstellung wird aktualisiert.DefaultListModel listModel = new DefaultListModel();JList list = new JList(listModel);add(new JScrollPane(list), BorderLayout.SOUTH);

JList wird meistens in JScrollPaneeingebettet (scrollbare Liste)

public void buttonHinzu_actionPerformed(ActionEvent e) {listModel.addElement(eingabe.getText());

}

Listenmodell: ein Object für jede Zeile; toString() wird für die Anzeige verwendet.

39se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

JComboBox

JComboBox repräsentiert Comboboxen (Kombinationen aus Eingabefeld und Liste).

Als Auswahlmöglichkeiten können beliebige Objects angegeben werden; toString() wird für die Anzeige verwendet.

JComboBox comboBox1 = new JComboBox();comboBox1.addItem("Rote Auswahl");comboBox1.addItem("Gelbe Auswahl");comboBox1.addItem("Blaue Auswahl");add(comboBox1);

JComboBox comboBox2 = new JComboBox();comboBox2.addItem("Rote Auswahl");comboBox2.addItem("Gelbe Auswahl");comboBox2.addItem("Blaue Auswahl");comboBox2.setEditable(true);add(comboBox2);

Nur vorgegebene Auswahlmöglichkeiten

Vorgegebene Auswahlmöglichkeiten undfreie Eingabemöglichkeit

40se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

JTable

Mit JTable steht eine leistungsfähige Tabellen-Komponente zur Verfügung.In der „einfachen Variante“ wird der Tabelleninhalt als Array vorgegeben:

Eigene Tabellen- und Spaltenmodelle ermöglichen den Umgang mit komplexen Daten und bieten mehr Kontrolle über Aufbau und Darstellung der Tabelle.

setLayout(new BorderLayout(5, 5));String[][] inhalt = { { "Audi", "A3 1,9 TDI", "S-HD 3273" },

{ "Mercedes", "CLK 200 K", "ES-XA 177" }, ... };String[] spalten = { "Hersteller", "Modell", "Kennzeichen" };JTable table = new JTable(inhalt, spalten);add(new JLabel("Fuhrpark:"), BorderLayout.NORTH);add(new JScrollPane(table), BorderLayout.CENTER);

Tabelleninhalt und Spaltenbeschriftungen

Einbettung in JScrollPane

41se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Eigene Tabellenmodelle: TableModel

Eigene Tabellenmodelle müssen die Schnittstelle TableModelimplementieren. Die Klasse DefaultTableModel bietet Standardimplementierungen für die in TableModel definierten Methoden und eignet sich in vielen Fällen als Basisklasse für eigene Tabellenmodelle.In TableModel definierte Methoden, die oft überlagert werden:

getRowCount(), getColumnCount() – liefern die Zahl der Zeilen/Spalten in der Tabelle zurückgetValueAt(zeile, spalte) – liefert den Inhalt der angegebenen Tabellenzelle zurückgetColumnName(spalte) – liefert die Bezeichnung der angegebenen Spalte zurück

Wenn sich die Tabellendaten oder die Tabellenstruktur (Spalten etc.) des Tabellenmodells ändern, müssen die JTable-Objektebenachrichtigt werden, damit die Tabellen neu „gezeichnet“ werden:fireTableDataChanged(); // Daten/Zeilenzahl geändert

fireTableStructureChanged(); // Struktur geändert

42se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Beispiel: Quadratzahlen-Tabelle

Tabelle, die eine beliebig wählbare Zahl von Quadratzahlen darstelltNur wenige Tabellenzellen sind „sinnvoll“ gefülltTabelleninhalt ist dynamisch: bei Angabe einer anderen Obergrenze muss die Tabelle neu gezeichnet werden.

Benutzer kann Obergrenze der Quadratzahlen selbst wählen

43se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Tabellenmodell für Quadratzahlen-Tabelle (1)

class QuadratzahlenTableModel extends DefaultTableModel {private int max;public EinmaleinsTableModel(int n) { max = n; }public int getRowCount() { return max; }public int getColumnCount() { return max; }public Object getValueAt(int row, int column) {

if (row == column) {return String.valueOf((row + 1) * (column + 1));

} else {return "-";

}}public String getColumnName(int column) {

return String.valueOf(column + 1);}public void setMax(int n) {

max = n;fireTableStructureChanged();

}}

Eigene TableModel-Implementierung auf Basis von DefaultTableModel

Eigene “sinnvolle”Implementierungder vorgegebenenMethoden

liefertQuadratzahlen

Benachrichtigt JTable-Objekte, dass sich die Struktur der Tabelle(Spaltenzahl) geänderthat und die Tabelle neugezeichnet werden muss

44se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Tabellenmodell für Quadratzahlen-Tabelle (2)

...final QuadratzahlenTableModel modell =

new QuadratzahlenTableModel(10);JTable tabelle = new JTable(modell);add(new JScrollPane(tabelle));...buttonMax.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {int max = Integer.parseInt(feldMax.getText());modell.setMax(max);

}});...

Eigenes Tabellenmodellwird an JTable-Konstruktor übergeben

Modell wird geändert; Modell sorgt fürAktualisierung der Darstellung

Neben Tabellenmodellen können auf ähnliche Weise auch eigene Spaltenmodelle (Schnittstelle TableColumnModel) und eigene Zellen-Renderer (z. B. für farbige Tabellenzellen; Schnittstelle TableCellRenderer) implementiert werden.

45se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Swing und Threads

Swing-Anwendungen bestehen typisch aus drei Arten von Threads:Die Anwendung startet im Initial Thread.Im Event Dispatch Thread findet die Ereignisbehandlung der Swing-Oberfläche statt.Langlaufende Tätigkeiten werden als Hintergrund-Tasks in WorkerThreads ausgeführt.

Um Synchronisationsprobleme zu vermeiden, gilt: Sobald eine Swing-Komponente erstmalig dargestellt wird, sollten Zugriffe (Abfragen, Manipulationen etc.) darauf nur innerhalb des Event Dispatch Threadserfolgen!

public static void main(String[] args) {SwingUtilities.invokeLater(new Runnable() {

public void run() {MeinDialog dialog = new MeinDialog();dialog.setVisible(true);

}});

}

“Sauberer” Start von Swing-Anwendungen: Im Initial Thread(main-Methode) wird überinvokeLater() und einentsprechendes Runnable-Objektdafür gesorgt, dass die Swing-Oberfläche erst im EDT erzeugt wird.

46se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

Arbeiten im Hintergrund: SwingWorker

Wenn langlaufende Tätigkeiten im EDT ausgeführt werden, ist die Swing-Oberfläche während der Ausführung „blockiert“.Entsprechende Arbeiten sollten deshalb an asynchrone Hintergrund-Tasks ausgelagert werden. Hierzu dient die abstrakte Klasse SwingWorker.SwingWorker<T, V> ist zweifach typisiert: T ist der Ergebnistyp des Threads, V der Typ möglicher Zwischenergebnisse.Die Methode T doInBackground() wird in einem eigenen Threadausgeführt: hier findet die eigentliche (langlaufende) Tätigkeit statt. Die Swing-Oberfläche ist nicht „blockiert“, da Ereignisse weiterhin vom EDT verarbeitet werden können.Die Methode void done() wird im EDT aufgerufen, sobald die Tätigkeit beendet ist: hier kann das Ergebnis mit get() abgerufen und z. B. durch Zugriff auf Swing-Komponenten „gefahrlos“ dargestellt werden.

Weitere Möglichkeiten von SwingWorker: http://java.sun.com/docs/books/tutorial/uiswing/concurrency/index.html

47se

Prog

ram

men

twic

klun

gW

inte

r 2008/2

009

©H

olge

r Röd

er

SwingWorker-Beispielclass DirSizeWorker extends SwingWorker<Long, Void> {

protected String dir;public DirSizeWorker(String dir) { this.dir = dir; }protected long count(File f) {

long size = 0;if (f.isFile())

size = f.length();else if (f.isDirectory()) {

for (File c : f.listFiles()) { size += count(c); } }return size;

}protected Long doInBackground() throws Exception {

return count(new File(dir));}protected void done() {

try {labelSize.setText(

String.format("Größe: %d Bytes%n", get()));} catch (Exception exception) { }

}}DirSizeWorker worker = new DirSizeWorker(textDir.getText());worker.execute();

Eigene SwingWorker-Implementierung: Ergebnistyp Long

Langlaufende Methode(berechnet rekursivVerzeichnisgröße)

Wird in eigenem Thread ausgeführt, liefert Verzeichnisgröße als Ergebnis

Wird im EDT ausgeführt, sobald das Ergebnis vorliegt

Ergebnis abrufen, in Swing-Oberfläche darstellen

Worker-Objekt erzeugen und ausführen (z.B. innerhalb einer actionPerformed()-Methode)