Holger Röder Java: Kapitel 7 Grafische ... · PDF fileHolger Röder Java: Kapitel 7...
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)