1 / 63

Grundlagen der Informatik 1 Thema 21: GUI und verschachtelte Klassen

Grundlagen der Informatik 1 Thema 21: GUI und verschachtelte Klassen. Prof. Dr. Max Mühlhäuser Dr. Guido Rößling. AWT und Swing. AWT = Abstract Window Toolkit Package java.awt Benutzt Steuerelemente des darunterliegenden Betriebssystems

kineks
Download Presentation

Grundlagen der Informatik 1 Thema 21: GUI und verschachtelte Klassen

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Grundlagen der Informatik 1Thema 21: GUI und verschachtelte Klassen Prof. Dr. Max Mühlhäuser Dr. Guido Rößling

  2. AWT und Swing • AWT = Abstract Window Toolkit • Package java.awt • Benutzt Steuerelemente des darunterliegenden Betriebssystems • Native Code (= direkt für die Maschine geschrieben, keine VM) • schnell • Aussehen (Look) hängt vom System ab: unterschiedliche Schriften, … • Portabilität eingeschränkt • Swing • Package javax.swing (Teil der Java Foundation Classes) • Merkmal: Swing-Klassen beginnen mit „J“: JButton, ... • Vollständig in Java programmiert, eigener Look • Baut auf AWT auf • Verwendet ein Minimum an systemspezifischen Komponenten

  3. Komponenten • Einige oft verwendete Komponenten und für welche Interaktionsaufgaben sie verwendet werden • Anzeigen von Textund Symbolen • JLabel • Auslösen von Aktionen • JButton • JMenu • JMenuItem

  4. Komponenten • Eingabe von Text • JTextField • Auswahl aus einer festen Menge von Optionen • JCheckBox • Auswahl aus einer variablen Menge • JList gegenseitig ausschließend: JRadioButton JComboBox Button oder TextField +ausklappbare Listbox

  5. Menschliche Faktoren • Beim Entwurf interaktiver Programme gibt es neben der funktionalen Vollständigkeit und Korrektheit viele zusätzliche Aspekte zu beachten • Dazu gehört die Art und Weise der Interaktion und wie leicht sie zu erlernen und benutzen ist • Richtlinien für gute GUIs sind u.a.: • Vermeide Modi. Allgemein sinnvolle Operationen sollten immer verfügbar sein. • Biete einfache und durchgängige Interaktionssequenzen an. • Überfordere den Benutzer nicht durch zu viele Optionen. • Zeige bei jeder Interaktionsstufe klar die verfügbaren Optionen. • Gib dem Benutzer angemessene Rückmeldungen. • Gib dem Benutzer die Möglichkeit, Fehler problemlos rückgängig zu machen.

  6. Anatomie einer GUI-Applikation • Komponenten • Container • Ereignisse • Listener • Layout • Legt die Anordnungder Komponenten fest • Look & Feel • Legt das Aussehender Komponenten fest • getrennt: Anwendungslogik GUI-Framework Netz von kooperierenden Objekten mit klar festgelegten Zuständigkeiten: Container Komponenten Ereignisse Methodenaufrufe auf Komponente Anwendungslogik Listener Zustand: wert=3

  7. Fäden (Threads) • Sequentielle Programme • haben Anfang, definierte Ausführungssequenz und Ende. • Zu jedem Zeitpunkt ist genau eine Anweisung aktiv. • Ein Faden (Thread) ist ein einzelner sequentieller Kontrollfluss in einem Programm. • Nebenläufige Programme • Programme können mehrere Fäden besitzen. • Mehrere Programmteile können so quasi gleichzeitig ablaufen. Faden Programm Fäden Programm

  8. Fäden (Threads) • Fäden (Threads)… • nutzen die Ressourcen des Prozesses mit, in dem sie ablaufen • besitzen keine eigenen Speichersegmente • verfügen über einen eigenen Registersatz (inkl. Programmzähler und Statusregister) sowie einen eigenen Stack • werden oft auch als leichtgewichtige Prozesse (lightweightprocesses) bezeichnet. • GUI-Applikationen besitzen neben dem Haupt-Thread einen sogenannten Event-Dispatching Thread • Dieser Thread ruft Methoden der Anwendung auf, wenn bestimmte Ereignisse auftreten (Callback) • Die Ereignisbehandlungsroutinen in der Anwendung werden sequentiell ausgeführt • Das Zeichnen von Komponenten wird ebenfalls im Kontext dieses Threads ausgeführt

  9. Programmiermodell Anwendung GUI-Framework (SWING) main main Komponente einfügen AWT-EventQueue AWT-EventQueue Ereignis: Komponente zeichnen AWT-EventQueue Ereignis: Benutzereingabe

  10. Fenster importjavax.swing.JFrame; publicclassGUITestextendsJFrame { // The width of the window in pixels public static final intWIDTH = 400; // The height of the window in pixels public static final intHEIGHT = 300; // Constructs a new window with a given title publicGUITest(String title) { super(title); } // Start test application. Creates a new window and displays it publicstaticvoidmain(String args[]) { // Construct a new window. It is initially invisible GUITesttheWindow = newGUITest("My first GUI Application"); // Setwidth and height of the window theWindow.setSize(WIDTH, HEIGHT); // Open the window theWindow.setVisible(true); System.out.println("Exiting main..."); } }

  11. Fenster • Wir beobachten... • main() wird verlassen, das Programm läuft aber weiter. • Mehrere Fäden.Der Event-Dispatching Thread läuft weiter. • Klick auf Schließen-Button beendet das Programm nicht. • Ereignisverarbeitung fehlt.Genaueres dazu später.

  12. Container • Container und Komponenten • JFrame: „top levelcontainer“ • benutzt Fenster vom Betriebssystem • JPanel: „intermediate container“ • dient zum Gruppieren und Anordnen von Komponenten • Verschachtelung möglich • JLabel, JButton, ...: „atomare Komponenten“ • präsentieren dem Benutzer Informationen • erlauben oft Interaktion und Eingabe (Steuerelemente) • Container-Hierarchie • Selbst die einfachste Anwendung besteht auseiner Hierarchie von Containern und Komponenten • (Darstellung vereinfacht. Die Container zwischen JFrame und JPanel werden hier nicht weiter betrachtet) JFrame JPanel JLabel JFrame ... JPanel JLabel

  13. Komponenten • Hinzufügen von Komponenten • Der JFrame erzeugt automatisch ein JPanel,das „contentPane“. • Darin kann die Anwendung neueKomponenten einfügen. • Die Komponenten werden eingefügt, währenddas Fenster noch unsichtbar ist, also zwischendem Erstellen des Fenster-Objekts mit new undder Anzeige mit setVisible(true). • JLabels • stellen Text oder/und Symbole dar • sind passive Komponenten, erlauben keine Interaktion JFrame ... contentPane JPanel JLabel

  14. Labels importjava.awt.Container; importjavax.swing.JFrame; importjavax.swing.JLabel; public classGUITestextendsJFrame { publicGUITest(String title) { super(title); // Retrieve the area where one can add elements Container pane = getContentPane(); // Create a new label that displays help information JLabel label = newJLabel( "Press the [X] in the top right corner to exit"); // Add the label to the content of the window pane.add(label); } // ... }

  15. Buttons importjava.awt.Container; importjavax.swing.JButton; importjavax.swing.JFrame; importjavax.swing.JLabel; publicclassGUITestextendsJFrame { publicGUITest(String title) { super(title); Container pane = getContentPane(); JLabel label =newJLabel( "Press the [Exit] or [X] in the top right corner to exit"); pane.add(label); // Create a new push button that may be used in addition to the [X] JButton button = newJButton("Exit"); // Add the button to the content of the window pane.add(button); } // ... }

  16. Layout • Wir beobachten... • Der Text ist nicht mehr sichtbar, denn der Button liegt darüber! • Layout-Management • ist der Prozess, die Größe und Position von Komponenten zu bestimmen. • Das gewünschte Layout wird durch Zuordnung eines Layout-Objekts zum Container festgelegt:Container pane = getContentPane();pane.setLayout(newGridLayout(ROWS, COLS)); • Die Layout-Klasse implementiert das Interface LayoutManager.

  17. Vordefinierte Layouts • GridLayout • Ordnet die Komponenten in einemrechteckigen Gitter an. • Die Reihenfolge des Einfügens derKomponenten bestimmt ihre Anordnung. • BorderLayout • Positioniert in 5 Regionen jeweilsmaximal eine Komponente • Die Regionen N, E, S und W werdenso klein wie möglich gehalten. Derrestliche Platz entfällt auf CENTER. • Zuordnung zu einer Region durch zusätzlichen Parameter beim Aufruf von Container.add:add(new Button("SOUTH"), BorderLayout.SOUTH); • Weitere Layouts: BoxLayout, FlowLayout, GridBagLayout, ... • Siehe die Java API Dokumentation und die Tutorials für mehr Informationen

  18. GridLayout importjava.awt.Container; importjava.awt.GridLayout; importjavax.swing.JButton; importjavax.swing.JFrame; importjavax.swing.JLabel; publicclassGUITestextendsJFrame { publicGUITest(String title) { super(title); Container pane = getContentPane(); // Define a LayoutManager that places new elements properly // onto the pane. Here we use a grid with 3 rows and 1 column. pane.setLayout(newGridLayout(3, 1)); JLabel label = newJLabel( "Press the [Exit] or [X] in the top right corner to exit"); pane.add(label); JButton button = newJButton("Exit"); pane.add(button); } ... }

  19. Ereignisse (Events) • Jedesmal, wenn der Benutzer eine Taste drückt oder die Maus bewegt, tritt ein Ereignis ein. • Steuerelemente können Maus- und Tastatur-Ereignisse verarbeiten und neue Ereignisse erzeugen. • Beispiel: Befindet sich der Mauszeiger über einem Button und die Maustaste wird losgelassen, dann wird ein ActionEvent erzeugt. • Ereignisse werden durch Event-Objekte beschrieben • Die zugehörigen Klassen sind von java.awt.AWTEvent abgeleitet. (für GUI; allgemeiner: java.util.EventObject) • Der Typ gibt Auskunft über die Art des Ereignisses:ActionEvent: Benutzer klickt einen Button, drückt Return in einem Textfeld, wählt einen Menüeintrag, ...WindowEvent: Benutzer schließt Fenster, ...... • Die Attribute geben zusätzliche Informationen über das Ereignis, z.B. welcher Button gedrückt wurde.

  20. Listener • Mehrere Listener können sich bei einer Ereignis-Quelle (eventsource) registrieren und werden von diesem Zeitpunkt an über Ereignisse eines bestimmten Typs informiert. • Programmieren eines Listeners: • Das Klasse des Empfänger-Objekts (eventlistener) muss das dem Ereignistypen entsprechende Interface implementieren. • Z.B. für ActionEvents das Interface ActionListener. • Die Klasse muss alle Methoden des Interface implementieren. • Der Klient registriert nun das Empfänger-Objekt bei der Ereignis-Quelle. Z.B. mittels addActionListener(Listener) event listener event object event source event listener event listener

  21. Ereignisse importjava.awt.Container; importjava.awt.GridLayout; importjava.awt.event.ActionEvent; importjava.awt.event.ActionListener; importjavax.swing.JButton; importjavax.swing.JFrame; importjavax.swing.JLabel; publicclassGUITestextendsJFrame { publicGUITest(String title) { super(title); Container pane = getContentPane(); pane.setLayout(newGridLayout(3, 1)); JLabel label = newJLabel( "Press the [Exit] or [X] in the top right corner to exit"); pane.add(label); pane.add(newJButton("Exit")); // Create another button that changes the text of the Label JButton button = newJButton("Change Label Text"); // Now, define what should happen if the button is pressed button.addActionListener(newChangeButtonListener()); pane.add(button); } privateclassChangeButtonListenerimplementsActionListener { publicvoidactionPerformed(ActionEvent event) { System.out.println("Change Label Text was clicked"); } } // ... } Das ist eine verschachtelte Klasse (nestedclass). Später mehr dazu!

  22. View-Updates • Die durch Komponenten dargestellten Informationen und ihr Aussehen können durch Aufrufen ihrer Methoden verändert werden. • JLabel-API (Auszug):

  23. Ereignisse importjava.awt.Container; importjava.awt.GridLayout; importjava.awt.event.ActionEvent; importjava.awt.event.ActionListener; importjavax.swing.JButton; importjavax.swing.JFrame; importjavax.swing.JLabel; publicclassGUITestextendsJFrame { private JLabelinfoLabel; publicGUITest(String title) { super(title); Container pane = getContentPane(); pane.setLayout(newGridLayout(3, 1)); infoLabel = newJLabel( "Press the [Exit] or [X] in the top right corner to exit"); pane.add(infoLabel); pane.add(newJButton("Exit")); // Create another button that changes the text of the Label JButton button = newJButton("Change Label Text"); // Now, define what should happen if the button is pressed button.addActionListener(newChangeButtonListener()); pane.add(button); } privateclassChangeButtonListenerimplementsActionListener { publicvoidactionPerformed(ActionEvent event) { infoLabel.setText("You clicked the button!Now [Exit] or [X]"); } } // ... }

  24. Window-Events • Beim Klicken auf den Schließen-Button soll das Programm nun korrekt beendet werden. Registrieren eines WindowListeners • Interface WindowListener:

  25. Adapter • Beim Verwenden von Interfaces müssen immer alle Methoden implementiert werden. Das ist oft unpraktisch, deshalb existieren Adapter. • WindowAdapter… • implementiert WindowListener • definiert alle Methoden mit leerem Rumpf und somit ohne Verhalten • ist eine abstrakte Klasse. • Der anwendungsspezifische Event-Handler wird nun von WindowAdapter abgeleitet und überschreibt nur die „interessanten“ Methoden.

  26. WindowEvents importjava.awt.Container; importjava.awt.GridLayout; importjava.awt.event.ActionEvent; importjava.awt.event.ActionListener; importjavax.swing.JButton; importjavax.swing.JFrame; importjavax.swing.JLabel; importjava.awt.event.WindowAdapter; importjava.awt.event.WindowEvent; publicclassGUITestextendsJFrame { privateJLabelinfoLabel; publicGUITest(String title) { super(title); // Now, also define that the [X] terminatestheprogramcorrectly addWindowListener(newMyWindowListener()); Container pane = getContentPane(); pane.setLayout(newGridLayout(3, 1)); infoLabel = newJLabel( "Press the [Exit] or [X] in the top right corner to exit"); pane.add(infoLabel); // Create a new push button that may be used in addition to the [X] JButton button = newJButton("Exit"); // Define that the program should exit if you click the button button.addActionListener(newExitButtonListener()); pane.add(button);

  27. Window Events // Create another button that changes the text of the Label button = newJButton("Change Label Text"); // Now, define what should happen if the button is pressed button.addActionListener(newChangeButtonListener()); pane.add(button); } privateclassChangeButtonListenerimplementsActionListener { publicvoidactionPerformed(ActionEvent event) { infoLabel.setText("You clicked the button!Now [Exit] or [X]"); } } // Exit the program when the window close button is clicked classMyWindowListenerextendsWindowAdapter { publicvoidwindowClosing(WindowEvent e) { System.exit(0); } } // Exit the program when the “Exit”-button is clicked classExitButtonListenerimplementsActionListener { publicvoidactionPerformed(ActionEvent event) { System.exit(0); } } public static void main(String args[]) { GUITesttheWindow = newGUITest("My first GUI Application"); theWindow.setSize(WIDTH, HEIGHT); theWindow.setVisible(true); } publicstaticfinalint WIDTH = 400; publicstaticfinalint HEIGHT = 300; }

  28. Verschachtelte Klassen: Motivation • Die GUI Komponenten erwarten als “Listener” eine Instanz von XYZListener (z.B. ActionListener) • Wie können wir ein passendes Listener Objekt erstellen? • Option 1: Frame-Klasse implementiert das Listener Interface direkt • Option 2: Externe Klasse implementiert das Listener Interface

  29. Option 1: Frame-Klasse implementiertdas Listener Interface direkt importjava.awt.Container; importjava.awt.GridLayout; importjava.awt.event.ActionEvent; importjava.awt.event.ActionListener; importjavax.swing.JButton; importjavax.swing.JFrame; importjavax.swing.JLabel; publicclassGUITestextendsJFrameimplementsActionListener { publicGUITest(String title) { super(title); Container pane = getContentPane(); pane.setLayout(newGridLayout(3, 1)); JLabel label = newJLabel( "Press the [Exit] or [X] in the top right corner to exit"); pane.add(label); pane.add(new JButton("Exit")); // Create another button that changes the text of the Label JButton button = newJButton("Change Label Text"); // Now, define what should happen if the button is pressed button.addActionListener(this); pane.add(button); } publicvoidactionPerformed(ActionEvent event) { System.out.println("Change Label Text was clicked"); } // ... }

  30. Option 1: Frame-Klasse implementiertdas Listener Interface direkt • Diese Möglichkeit funktioniert zwar, ist aber im Allgemeinen unbefriedigend • Was ist, wenn es mehr als einen Button gibt? • Klasse kann nicht zwei actionPerformed Methoden haben! • Es gibt nicht nur Buttons, sondern auch Labels, Menus, … • Frame-Klasse implementiert eine Menge an Interfaces, die nichts mit seiner eigentlichen Funktionalität zu tun haben • action-Methoden müssen public sein, obwohl es eigentlich Implementationsdetails sind, die nicht zur Schnittstelle von Frame gehören • Im Allgemeinen ist dies eine schlechte Lösung

  31. Option 2: Externe Klasse implementiertdas Listener Interface importjava.awt.Container; importjava.awt.GridLayout; importjava.awt.event.ActionEvent; importjava.awt.event.ActionListener; importjavax.swing.JButton; importjavax.swing.JFrame; importjavax.swing.JLabel; publicclassGUITestextendsJFrame { privateJLabelinfoLabel; publicGUITest(String title) { super(title); Container pane = getContentPane(); pane.setLayout(newGridLayout(3, 1)); infoLabel = newJLabel( "Press the [Exit] or [X] in the top right corner to exit"); pane.add(infoLabel); pane.add(new JButton("Exit")); // Create another button that changes the text of the Label JButton button = newJButton("Change Label Text"); // Now, define what should happen if the button is pressed button.addActionListener(newChangeButtonListener()); pane.add(button); } } classChangeButtonListenerimplementsActionListener { publicvoidactionPerformed(ActionEvent event) { infoLabel.setText("You clicked the button!Now [Exit] or [X]"); } }

  32. Option 2: Externe Klasseimplementiert das Listener Interface • Hat nicht die konzeptuellen Nachteile von Option 1 • z.B. kein Problem, unterschiedliche Aktionen für unterschiedliche Buttons zu definieren • Das Interface des Frames wird nicht verunstaltet • Nachteile dieses Ansatzes • Führt zu sehr vielen Klassen • Übersichtlichkeit leidet • Geringere Kohäsion • Externe Listener-Klasse wird evtl. nur an genau einer Stelle benutzt • Aufwändig und lästig, für jeden Listener eine eigene Klasse anzulegen • Zugriff auf Instanzvariablen/Methoden/lokale Variablen der Frame Klasse aufwändig • Alles muss explizit im Konstruktor übergeben werden

  33. Option 2: Externe Klasseimplementiert das Listener Interface importjava.awt.Container; importjava.awt.GridLayout; importjava.awt.event.ActionEvent; importjava.awt.event.ActionListener; importjavax.swing.JButton; importjavax.swing.JFrame; importjavax.swing.JLabel; publicclassGUITestextendsJFrame { privateJLabelinfoLabel; publicGUITest(String title) { super(title); Container pane = getContentPane(); pane.setLayout(newGridLayout(3, 1)); infoLabel = newJLabel( "Press the [Exit] or [X] in the top right corner to exit"); pane.add(infoLabel); pane.add(newJButton("Exit")); // Create another button that changes the text of the Label JButton button = newJButton("Change Label Text"); // Now, define what should happen if the button is pressed button.addActionListener(newChangeButtonListener(infoLabel)); pane.add(button); } } classChangeButtonListenerimplementsActionListener { privateJLabelinfoLabel; publicChangeButtonListener(JLabel l) { infoLabel = l; } publicvoidactionPerformed(ActionEvent event) { infoLabel.setText("You clicked the button!Now [Exit] or [X]"); } }

  34. Verschachtelte Klassen • Beide Möglichkeiten (Option 1 + Option 2) sind nicht zufriedenstellend • Dies war die Hauptmotivation für Sun, mit Java 1.1 die verschachtelten Klassen (nestedclasses) einzuführen • Verschachtelte Klassen sind Klassen innerhalb von Klassen • Werden deklariert wie ganz normale Klassen, außer dass sie innerhalb anderer Klassen stehen • Einige Zugriffsregeln sind anders • Verschachtelte Klassen haben Zugriff auf Instanzvariablen/Methoden der äußeren Klasse

  35. Verschachtelte Klassen importjava.awt.Container; importjava.awt.GridLayout; importjava.awt.event.ActionEvent; importjava.awt.event.ActionListener; importjavax.swing.JButton; importjavax.swing.JFrame; importjavax.swing.JLabel; publicclassGUITestextendsJFrame { privateJLabelinfoLabel; publicGUITest(String title) { super(title); Container pane = getContentPane(); pane.setLayout(new GridLayout(3, 1)); infoLabel = newJLabel( "Press the [Exit] or [X] in the top right corner to exit"); pane.add(infoLabel); pane.add(newJButton("Exit")); // Create another button that changes the text of the Label JButton button = newJButton("Change Label Text"); // Now, define what should happen if the button is pressed button.addActionListener(newChangeButtonListener()); pane.add(button); } privateclassChangeButtonListenerimplementsActionListener { publicvoidactionPerformed(ActionEvent event) { infoLabel.setText("You clicked the button!Now [Exit] or [X]"); } } // ... } • Nested Class kann “private” sein • Klasse nur innerhalb der umschließenden Klasse sichtbar • hat Zugriff auf private Instanzvariable der umschließenden Klasse

  36. Verschachtelte Klassen • Jede verschachtelte Klasse benötigt bei der Instanziierung eine Referenz auf eine Instanz der umschließenden Klasse • Bei Instanziierung innerhalb der umschließenden Klasse wird diese Referenz implizit übergeben • Außerhalb einer umschließenden Klasse als enclInstance.newMyInnerClass() • Der Typ einer nested Class N innerhalb C ist “C.N” • Innerhalb von C reicht die Typdeklaration N (implizites Scoping) • Daumenregel: Wenn der Name einer nestedclass außerhalb der umschließenden Klasse benötigt wird, hat man etwas falsch gemacht. • Verschachtelte Klassen können auch als “static” deklariert werden • Semantik analog zu staticmethod: Kein Zugriff auf Instanzvariablen der äußeren Klasse, sondern nur auf static Methoden/Variablen

  37. Anonyme verschachtelte Klassen importjava.awt.Container; importjava.awt.GridLayout; importjava.awt.event.ActionEvent; importjava.awt.event.ActionListener; importjavax.swing.JButton; importjavax.swing.JFrame; importjavax.swing.JLabel; publicclassGUITestextendsJFrame { publicGUITest(String title) { super(title); finalJLabelinfoLabel; // now a local variable Container pane = getContentPane(); pane.setLayout(newGridLayout(3, 1)); infoLabel = newJLabel( "Press the [Exit] or [X] in the top right corner to exit"); pane.add(infoLabel); pane.add(newJButton("Exit")); // Create another button that changes the text of the Label JButton button = newJButton("Change Label Text"); // Now, define what should happen if the button is pressed button.addActionListener(newActionListener() { public void actionPerformed(ActionEvent event) { infoLabel.setText("You clicked the button!Now [Exit] or [X]"); } }); pane.add(button); } }

  38. Anonyme verschachtelte Klassen • Man kann innerhalb von Methoden anonyme Klassen anlegen • Diese haben keinen Namen • Sie werden nur über Supertypen angesprochen • Syntax: newSuperClassName(args) { … } odernew InterfaceName() { … } • Erzeugt implizit eine Subklasse der angegebenen Superklasse bzw. eine Klasse, die das angegebene Interface implementiert • Gleichzeitig wird eine Instanz der anonymen Klasse erzeugt • Diese Klasse kann über den angegebenen Superklassen/Interface Namen benutzt werden • Sogar lokale Variablen der Methode können in der Implementierung verwendet werden, sofern sie als “final” deklariert sind

  39. Anonyme verschachtelte Klassen • Vorteil gegenüber “normalen” verschachtelten Klassen • Wenn die Klasse nur an einem einzigen Ort benötigt wird, wird kein Name “verschwendet” • Definition der Klasse “on the fly” – dort wo sie benötigt wird • Einfacher Zugriff auf lokale Variablen / Methodenparameter • Anonyme Klassen kommen dem “lambda” aus Scheme recht nahe • Mit “lambda” können in Scheme Prozeduren “on the fly” definiert werden

  40. Kompilierung von verschachtelten Klassen • Wenn eine verschachtelte Klasse kompiliert wird, bekommt man für jede verschachtelte Klasse ein eigenes .classfile mit dem Namen “OuterClass$InnerClass.class” • Wenn eine anonyme Klasse kompiliert wird, heißt das File “OuterClass$n.class”, wobei n eine ganze Zahl ist • Intern (auf JVM Ebene) gibt es keine verschachtelten Klassen • Der Compiler transformiert intern den Code • Für jede verschachtelte Klasse wird eine Top-Level Klasse angelegt, die alle benötigten Argumente im Konstruktor übergeben bekommt

  41. GUI und Software Design • GUIs können sehr aufwändig und kompliziert sein • Die eigentliche Anwendung ebenfalls • Wie strukturiert man eine Anwendung mit komplexer GUI? • Regel Nr.1: Trennen Sie die Anwendungslogik von der Präsentationslogik

  42. GUI Antipatterns • Sie machen etwas falsch, wenn… • Sie in ihrer GUI-Klasse auf eine Datenbank zugreifen • Ihre GUI-Klasse mehr als 50 KB groß ist • in der GUI-Klasse Geschäftsprozesse implementiert werden • Ihre Anwendungsdaten in GUI-Klassen gespeichert sind • … • Besser: Schichtenarchitektur • z.B. sog. “Model-View-Controller Architektur” • trennt Daten/Anwendungslogik von Interaktion mit Benutzer • Daten/Anwendungslogik hängt nicht von GUI ab • einfach, mehrere Views zu unterstützen • Austausch von Views einfach

  43. A B C 45 35 15 Model-View-Controller Controller View Event senden BehandeltNutzer- eingaben Anzeige controller updates Zugriff Aktualisieren Hinweisauf Änderung Model Anwendungsdatenund Verhalten

  44. MVC – Das Modell • Das Modell enthält die Daten • Hat Methoden, um auf Daten zuzugreifen und sie zu ändern • Benachrichtigt Listener/Observer, wenn sich die Daten ändern • Kann (Teile) der Geschäftsprozesse implementieren

  45. MVC – Der Controller • Verarbeitet die Eingaben des Benutzers • zum Beispiel Validierung, Interpretation jeglicher Art, … • Häufig zuständig für die Benutzerführung der GUI • Kommuniziert diese Eingaben zum Modell • Kann präsentationsnahe Teile der Anwendungslogik enthalten • z.B. Interaktionsfluss mit dem Benutzer • Scharfe Trennung vom Modell ist oft schwierig • Kann (muss aber nicht) spezifisch für eine feste GUI sein • Controller hat oder hat nicht eine Instanzvariable die auf die GUI zeigt • evtl. entkoppelt über Interface • Bessere Wiederverwendbarkeit im letzteren Fall • Schichtenstruktur

  46. MVC – Die View • Die View stellt eine visuelle Repräsentation des Modells dar • Es kann beliebig viele Views auf denselben Daten geben • z.B. mehrere Instanzen derselben View • Aber auch völlig unterschiedliche Views • Zum Beispiel können die Finanzen einer Firma als Tabelle oder als Graph dargestellt werden • Registriert sich beim Modell als Listener, zeichnet sich neu, wenn Modell sich ändert.

  47. Internationalization (I18N) • Internationalisierung: Bereitstellung von Inhalten in mehreren Sprachen • Problematisch für GUIs: was muss sich ändern? • Beispiel - Menüeintrag: • Text • [optionales] Icon • Kürzel (hier: ALT+G) • Tool tip (“Generate…”) • Englische Fassung:

  48. Internationalization (I18N) • Java bietet Basiselemente für Internationalization • Die GUI-Anpassung muss aber vom Programmierer erfolgen • Alternative: Nutzung des translator Package • Siehe die Beispiele auf den folgenden Folien • Grundlegender Ansatz: • Alle sprachspezifischen Elemente kommen in eine Datei • Eine Datei pro unterstützter Sprache • Die Zeilen der Datei sind im Format key=Wert • key: ein String, der das Element beschreibt • Wert: der auszugebende Wert für den key • Anstelle “echter” Texte wird im Code nur der key genutzt

  49. Sprachressourcen • Alle Ressourcen kommen in die sprachspezifische Datei • Diese Dateien haben alle den gleichen Basisnamen • Zum Beispiel “msg” • Die Dateierweiterung hat das Format land_SPRACHE • Deutsche Ressourcen stehen also in “msg.de_DE” • Die US-Englische Fassung steht in “msg.en_US” • … • Beispiel für einen Inhalt: msg.en_US msg.de_DE • hi=Hello! • query=How are you today? • hi=Hallo! • query=Wiegehtes Dir?

  50. translatorPackage: Translator • Ziel: Inhaltsübersetzung für eine Zielsprache • Nutzt java.util.Localefür die Sprachbestimmung • Vordefinierte Locales: Locale.GERMANY, Locale.US, … • Die Zielausgabe hängt ab von bis zu drei Attributen: • Sprache: “de”, “en”, “es”, … • Land: “de”, “us”, “uk”, … • Variante: spezifischer Code für Browser etc., z.B. „WIN” • Anlegen einer neuen Instanz von Translator • Parameter: Basisname der Ressourcen und Ziel-Locale: TranslatormyTrans = newTranslator(“msg”, Locale.GERMANY);

More Related