Oberflächenprogrammierung mit Swing
Transcription
Oberflächenprogrammierung mit Swing
Java für Fortgeschrittene Proseminar Sommersemester 2009 Oberflächenprogrammierung mit Swing Martin Sevenich Technische Universität München 3. Mai 2009 1 Zusammenfassung auf. Vor diesem Hintergrund wurde Swing von eiDieser Artikel gibt eine Einführung in Swing, ner Kooperation aus Sun Microsystems, Jadessen Features und grundsätzliche Aspekte vaSoft und Netscape Communications entder Oberflächenprogrammierung. wickelt und ist seit Version 1.2, neben etwa Java2D, Bestandteil von Java und gehört zu den Java Foundation Classes.[6] 2 Einleitung Swing behebt zwar viele Schwächen von AWT, ersetzt es aber nicht vollständig, sondern baut darauf auf, erweitert es um viele Aspekte und ermöglicht so die Entwicklung professioneller und auch komplexer grafischer Benutzeroberflächen. Da die Nutzer zur Interaktion mit JavaProgrammen nicht nur eine Konsole haben wollten, sondern ansprechend gestaltete Fenster mit Menüs und Knöpfen, wurde von Sun das Abstract Window Toolkit (AWT) Im Folgenden wird erst ein Überblick über entwickelt.[6] die Komponenten gegeben die Swing bietet. Zwar bietet AWT die Möglichkeit einfache Im Weiteren werden einige grundlegenden Oberflächen zu erstellen, doch weist es eini- Aspekte von Swing behandelt, wie Events, ge Schwächen auf, die zum Teil auf die sehr Layout-Manager oder Nebenläufigkeit. Abkurze Entwicklungszeit zurückzuführen sind. schließend wird ein Ausblick auf Effekte geSo müssen die Komponenten vom Be- geben, sowie das Demoprojekt vorgestellt. triebsystem bereitgestellt werden, was zu einer vergleichsweise geringen Anzahl an verfügbaren Komponenten führt. Des Weiteren weist AWT eine schlechte Performance 1 3 Aufbau Eine Komponente kann einem Container mit getContentPane().add(Component), oder Die wichtigsten Elemente in Swing sind alternativ mit add(Component) hinzugefügt JComponent und seine Unterklassen, die die werden, wobei beide Methoden äquivalent Komponenten darstellen, sowie JFrame und sind. JApplet die die Top-Level-Container bilden. public MyFrame ( ) { super ( ) ; Ein weiterer wichtiger Teil von Swing sind t h i s . getContentPane ( ) . add ( new JButton ( ” H a l l o Welt ” ) ) ; die, aus AWT übernommenen, Events und } Event-Listener die eine Reaktion auf Benutzeraktionen ermöglichen. Folgendes Beispiel zeigt, wie ein Verschachteln von Containern aussehen kann: Das JFrame enthält einen JButton und ein JPanel das auch wiederum zwei Buttons enthält. 4 Komponenten JFrame frame = new JFrame ( ”Top−L e v e l ” ) ; JPanel p a n e l = new JPanel ( ) ; frame . s e t L a y o u t (new GridLayout ( 1 , 2 ) ) ; 4.1 Top-Level-Container Um auf dem Bildschirm erscheinen zu können, müssen alle Komponenten Teil einer Komponenten-Hierarchie sein, deren Wurzel immer ein Top-Level-Container ist. TopLevel-Container sind Instanzen der Klassen JFrame, JDialog oder JApplet.[2] Dabei muss beachtet werden, dass Komponenten immer nur Teil eines Containers sein können. Falls eine Komponente bereits in einem Container vorhanden ist und dann einem anderen hinzugefügt wird, so verschwindet sie aus dem Ersten. frame . add ( p a n e l ) ; p a n e l . add (new JButton ( ” i n n e r Button ” ) ) ; p a n e l . add (new JButton ( ” i n n e r Button ” ) ) ; frame . add (new JButton ( ” o u t e r Button ” ) ) ; } Abb. 2: JPanel in einem JFrame 4.2 Allgemeines zu Swing-Komponenten Swing geht davon aus, dass alle Komponenten blickdicht (engl. opaque) sind und spart sich dadurch die Arbeit, den Bereich dahinter zu zeichnen. Das kann allerdings zu Problemen führen, falls diese (halb-) transparent oder nichtrechteckig sind, da in diesem Abb. 1: Beispielhierarchie 2 Fall Veränderungen hinter der Komponente nicht angezeigt werden. Um Swing mitzuteilen, dass es den Bereich dahinter auch zeichnet soll, muss setOpaque(boolean) auf true gesetzt werden.[7] Model: Der Mode-Teil beihaltet die Daten einer Komponente und regelt den Zugriff darauf. Beispielsweise kann auf die Daten eines JTree nur über ein TreeModelObjekt zugegriffen werden. Icons: Viele Swing-Komponenten können mit einem Icon versehen werden, einem kleinen Bild fester Größe. Eine nützliche Klasse ist hierfür ImageIcon, das die Icon-Schnittstelle implementiert. Diese Klasse erzeugt ein Icon aus einem GIFJPG- oder PNG-Bild.[2] Controler: Der Controler-Teil steuert die Eigenschaften einer Komponente und die ausgelösten Events. Tooltips: Um dem Benutzer auf einfache 4.3 Kontrollflächen Art und Weise die Funktion gewisser Komponenten zu erläutern, können JButton: Eine gewöhnliche Schaltfläche, Tooltips verwendet werden, die bei die einen Text und ein Icon anzeigen Pausieren des Mauszeigers eine kurkann und in ihren ursprünglichen Zuze Nachricht anzeigen. Tooltips können stand zurückkehrt, nachdem die Maus mit setToolTip(String) gesetzt werihn gedrückt hat. den.[2] JToggleButton: Ähnlich wie JButton, J L a b e l l a b e l = new J L a b e l ( ” L a b e l mit I c o n und T o o l t i p ” ) ; kann allerdings zwei Zustände annehl a b e l . s e t I c o n (new ImageIcon ( ” knut . png ” ) ) ; men, gedrückt bzw. nicht-gedrückt. l a b e l . s e t T o o l T i p T e x t ( ”Knut d e r E i s b ä r ” ) ; getContentPane ( ) . add ( l a b e l ) ; JCheckBox: Verhält sich ähnlich wie ein JToggleButton, wird jedoch durch eine plattformspezifische Grafik dargestellt. JRadioButton: Im Prinzip ähnlich wie eine JCheckBox. Normalerweise werden mehrere JRadioButtons zusammen verwendet, wobei diese einer ButtonGroup zugewiesen werden, so dass nur maximal ein JRadioButton der Gruppe auf einmal selektiert werden kann. Abb. 3: Label mit Icon und Tooltip Model-View-Controler: Swing verfolgt das Model-View-Controler-Konzept, dass die Darstellung und Steuerung einer Komponente von den Daten trennt die sie enthält. Abb. 4: verschiedene Kontrollflächen View: Der View-Teil beschreibt das Aussehen einer Komponente. 3 4.4 Textkomponenten einer HTML-Datei anzeigen. Um Text anzuzeigen, bietet Swing mehrere Klassen an: 4.5 Listen JLabel: Kann eine Zeile Text anzeigen, der vom Benutzer weder selektiert noch verändert werden kann. Bei Verwendung von HTML-Code können mehrere Zeilen, mehrere Schriftarten und Farben angezeigt werden. Zusätzlich kann dazu ein Icon angezeigt werden. Um mehrere Daten auf einmal anzuzeigen, bietet sich unter anderem die Klasse JList an, die Swing Listen zur Verfügung stellt. Die Daten werden dabei nicht von JList selber gespeichert, sondern in einem ListModel-Objekt, das von JList angezeigt werden kann.[2][4] JTextField: Kann eine Zeile Text anzeigen der vom Benutzer markiert und verändert werden kann. Ist eine Eingabe abgeschlossen wird ein ActionEvent ausgelöst. JList lässt nicht nur die Selektion eines Elementes zu. Mit setSelectionMode lässt sich die Einstellung mit dem entsprechenden Argument anpassen: SINGLE SELECTION: Lässt nur die Selektion eines Elementes zu. JTextField bietet zusätzlich folgende Unterklassen: SINGLE INTERVAL SELECTION: Lässt die Selektion von beliebig vielen zusammenhängenden Elementen zu. JFormattedTextField: Ermöglicht es die erlaubten Zeichen festzulegen JPasswordField: Alle eingegebenen MULTIPLE INTERVAL SELECTION: Zeichen werden als ein vordefinierLässt die Selektion von beliebigen tes Zeichen dargestellt Elementen an beliebigen Positionen zu. JComboBox: Bietet ein Drop-DownMenu zur Auswahl vordefinierter Die Ausrichtung der Listenelemente lässt sich mit setSelectionMode bestimmen. String Mögliche Argumente sind: JSpinner: Bietet zusätzlich 2 Knöpfe, die den Benutzer den vorherigen VERTICAL: Zeigt die Elemente untereinander an. oder den nächsten vordefinierten Wert auswählen lassen VERTICAL WRAP: Zeigt die Elemente untereinander an, allerdings in mehreren Spalten. Mit setVisibleRowCount(int) kann die Anzahl der Elemente pro Spalte festgelegt werden. JTextArea: Kann mehrere Zeilen anzeigen die vom Benutzer markiert und verändert werden können. Allerdings können nur eine Schriftart und Schriftfarbe verwendet werden. JEditorPane: Kann mehrere Zeilen Text HORIZONTAL WRAP: Zeigt die Elemente nebeneinander an, aber in mehund Bilder anzeigen mit verschiedenen reren Zeilen. Ansonsten wie VERTISchriftarten und Schriftfarben. Das JECAL WRAP. ditorPane kann auch Text entsprechend 4 4.6 Tabellen Blätter sein. Beide Arten werden durch Klassen repräsentiert, die die SchnittstelSwing unterstützt mit der Klasse JTable das le TreeNode implementieren, beispielsweise Anzeigen und wahlweise auch Verändern von DefaultMutableTreeNode Daten in einer Tabelle. JTable dient nur public MyFrame ( ) { super ( ”Obstbaum” ) ; zum Anzeigen der Daten und ist nicht für ihre Speicherung zuständig, dafür wird ein DefaultMutableTreeNode r o o t , a p f e l ; r o o t = new DefaultMutableTreeNode TableModel-Objekt verwendet.[2][4] ( ” Obst ” ) ; a p f e l = new DefaultMutableTreeNode ( ” Apfel ” ) ; r o o t . add (new DefaultMutableTreeNode ( ” Banane ” ) ) ; r o o t . add (new DefaultMutableTreeNode (” Zitrone ” ) ) ; r o o t . add ( a p f e l ) ; a p f e l . add (new DefaultMutableTreeNode ( ” r o t e r Apfel ” ) ) ; a p f e l . add (new DefaultMutableTreeNode ( ” g r ü n e r A p f e l ” ) ) ; Der Konstruktor von JTable erwartet entweder ein fertiges TableModel-Objekt oder ein String-Array, das die Spaltennamen spezifiziert, zusammen mit einem zweidimensionalen Object-Array, das die Werte der Zellen beinhaltet. Auf die Elemente der Tabelle kann durch das TableModel-Objekt mit den Methoden getValueAt(int,int) und setValueAt(int,int) der Klasse TableModel zugegriffen werden. JTree t r e e = new JTree ( r o o t ) ; add ( t r e e ) ; } Abb. 6: Beispiel für eine Baumstruktur Abb. 5: Beispiel einer Tabelle 5 Eigene Komponenten 4.7 Bäume Falls die von Swing angebotenen Komponenten nicht ausreichend sind, lassen sich durch Erben von der Klasse JComponent auch eigene Komponenten erstellen. Hierfür müssen nur die entsprechenden Methoden überschrieben werden, etwa paintComponent(Graphics g), um das Einträge im Baum können dabei Kno- Aussehen zu bestimmen. Um bereits vorten mit weiteren Unterelementen, oder handene Funktionalitäten zu nutzen, kann JTree stellt Daten in einer Baumstruktur dar, was sich vor allem für hierarchisch strukturierte Daten anbietet. Die Daten werden dabei nicht von JTree direkt gespeichert, sondern von einem Tree-ModelObjekt.[2][4] 5 auch von anderen Klassen, etwa JList nes Panel anzuzeigen. Auch kann man in geerbt werden.[3] den Dialogen ein Icon anzeigen und angeben, ob es sich um einen Informations-, Fehler-, Warnungs-, oder Frage-Dialog handelt, was bei verschiedenen Look-and-Feels anders an6 Dialoge gezeigt wird. Falls ein Programm eine sofortige Entscheidung oder Daten vom Benutzer braucht, bietet es sich an Dialoge zu verwenden, ein kleines Fenster, das Informationen ausgibt und/oder Eingaben vom Benutzer erwartet.[4] Swing bietet für die Erstellung von Dialogen die Klasse JOptionPane mit folgenden statischen Methoden an: Abb. 7: verschiedene Dialoge static int showConfirmDialog: Zeigt einen 7 Event-Listener Dialog an, der dem Benutzer mehrere Schaltflächen zur Auswahl gibt. Die Auswahl des Benutzers wird als int- Ein wichtiger Bestandteil von Oberflächen ist die Fähigkeit auf Aktionen des Benutzers Wert zurückgegeben. zu reagieren, etwa wenn eine Schaltfläche static String showInputDialog: Zeigt betätigt wird oder ein Schieberegler verstellt einen Dialog an, der dem Benutzer wird. Hierfür verwendet Java Events und eine Textzeile zur Eingabe gibt. Seine Listener. Events werden durch BenutzerakEingabe wird als String zurückgegeben. tionen, aber auch durch Java selbst erzeugt static Object showInputDialog: Nimmt und vom System nach unten zu den entspreals Argument ein Object-Array und chenden Listenern propagiert die sich dafür zeigt seine Elemente als Strings in ei- angemeldet haben.[2][6] nem Drop-Down-Menü an. Die Auswahl Ein Listener ist ein Objekt, das sich durch des Benutzers wird zurückgegeben. Verwendung einer Listener-Schnittstelle static void showMessageDialog: Gibt ei- beim System für eine bestimmte Art Events ne Nachricht in einem Dialog mit einem anmeldet. Durch Implementierung der durch OK-Button aus. die Schnittstelle erforderlichen Methoden kann der Listener auf die Events reagieren. static int showOptionDialog: Ähnlich public c l a s s M y S i m p l e L i s t e n e r implements A c t i o n L i s t e n e r { public void a c t i o n P e r f o r m e d ( ActionEvent a c t i o n ) { doSomething ( ) ; } } wie showConfirmDialog, allerdings wird ein Object-Array als Argument übergeben und dessen Elemente als Auswahlbuttons angeboten. Der Index des gewählten Objekts wird zurückgegeben. Da es je nach Event-Art sehr viele MethoAlternativ gibt es auch statische Methoden, den gibt, die implementiert werden müssen, um die oben erwähnten Dialoge als inter- obwohl sie möglicherweise nicht gebraucht 6 Abb. 8: Event-Model werden, kann es sich anbieten von einer first() und show() können die KarAdapter-Klasse zu erben, die wiederum eiten gewechselt werden. ne Listener-Schnittstelle implementiert und FlowLayout: Die Komponenten werden nealle nötigen Methoden schon leer implemenbeneinander in einer Zeile angeordnet. tiert hat. Ist zur Seite hin kein Platz mehr so wird public c l a s s MyListenerWithAdapter eine neue Zeile begonnen. extends MouseAdapter { public void mouseMoved ( MouseEvent mouse ) { doSomething ( ) ; } } GridLayout: Das GridLayout ordnet die Komponenten in einem Gitter aus gleich großen Zellen an, wobei die Höhe und Breite der Zellen von der Größe des Containers abhängen. Die Anzahl der Zeilen und Spalten wird im Konstruktor übergeben 8 Layout Manager Da das Positionieren der Komponenten GridBagLayout: Ähnlich wie beim GridLayout wird der zur Verfügung stehende mit absoluten Koordinaten umständlich Bereich in ein Gitter unterteilt, jedoch und unflexibel ist, bietet Swing eine mit weit weniger Einschränkungen. So Auswahl von Layout-Managern, die dem müssen beispielsweise nicht alle Zeilen Entwickler diese Arbeit abnimmt. Mit bzw. Spalten die gleiche Größe haben, setLayout(LayoutManager) kann ein Laydie Komponenten können nur einen Teil outManager gesetzt werden.[2] der Zellen ausfüllen und vieles mehr. BorderLayout: Das BorderLayout verwalSpringLayout: Im SpringLayout werden die tet bis zu 5 Komponenten. Je eine kann Beziehungen der Ränder der einzelnen im “Süden”, “Norden”, “Osten”, “WesKomponenten zueinander definiert. ten” oder im Zentrum angezeigt werBoxLayout: Das BoxLayout wurde entwiden. ckelt um eine Vielfalt ähnlich dem GridCardLayout: Die Komponenten werden in BagLayout zu bieten ohne dessen Komgleicher Größe als Karten hintereinanplexität zu übernehmen. Die Kompoder angeordnet, wobei nur jeweils die nenten werden je nach Wahl von links vorderste angezeigt wird. Mit den Menach rechts oder von oben nach unthoden next(), previous(), last(), 7 Folgendes Beispiel zeigt ein JFrame, das ein BorderLayout verwenden und im zentralen Feld ein JPanel einsetzt um mehrere JButtons in einer Gitterstruktur anzuzeigen. ten eingefügt, wobei versucht wird ihre Größe beizubehalten. Ist das nicht möglich wird die Größe angepasst. Zur Vereinfachung kann die Klasse Box verwendet werden, die eine Komponente mit einem BoxLayout darstellt. Nach Einfügen aller Komponenten kann mit Aufruf der Methode pack() abschließend die Größe des Containers entsprechend des Platzbedarfes angepasst werden. public c l a s s MyFrame extends JFrame { public MyFrame ( ) { s e t L a y o u t (new BorderLayout ( ) ) ; add ( southComponent , BorderLayout .SOUTH) ; add ( northComponent , BorderLayout .NORTH) ; add ( eastComponent , BorderLayout . EAST ) ; add ( westComponent , BorderLayout .WEST) ; add ( centerComponent , BorderLayout .CENTER) ; pack ( ) ; } } Abb. 10: verschachtelte Layout-Manager 9 Nebenläufigkeit in Swing 9.1 Swing Thread Design Um eine threadsichere grafische Oberfläche zu gewährleisten, ist es erforderlich, dass ein Thread ein Lock auf die Komponente erhält auf die er zugreifen möchte. Die Verwendung von Locks birgt allerdings einige Probleme: So bringen Locks auch stets die Gefahr von Deadlocks mit sich. Ein weiteres Problem besteht darin, dass das ständige Setzten und Lösen der Locks viel Zeit in Anspruch nimmt, was zu Lasten der Performance der Anwendung geht. Abb. 9: BorderLayout Verschachteln von Layouts: Um ein komplexes Layout zu erreichen, kann es oft einfacher sein die gewünschten Komponenten nicht direkt in den Container einzufügen, sondern diese auf weitere Container, meist JPanel zu verteilen. Durch diese Verschachtelung lassen sich verschiedene Layout-Manager miteinander kombinieren. Aus diesen Gründen ist Swing nicht threadsicher. Um trotzdem ein fehlerfrei funktionierendes Programm zu gewährleisten, sollte die Steuerung der grafischen Oberfläche nur durch einen Thread abgewickelt wer- 8 den, durch den so genannten Event Dispatch Thread (EDT). Da der EDT auch für die Verarbeitung der Events verantwortlich ist, sollten rechenintensive Operationen nicht auf dem EDT selber durchgeführt werden, da ein beschäftigter EDT keine Events mehr abarbeiten kann, was dazu führt, dass die Oberfläche “einfriert”.[2][5] den sollen, kann dafür die generische Klasse SwingWorker<T,V> verwendet werden. Die Klasse bietet folgende Methoden, die überschrieben werden sollten:[2][7] T ist dabei der Typ der von doInBackground() berechnet wird und V der Typ der Zwischenergebnisse der publish-Methode. Um gewährleisten zu können, dass auch bei Verwendung mehrer Threads nur der EDT abstract T doInBackground(): ähnlich wie die Methode run() der Klasse die Oberfläche steuert, bietet Swing mit der Thread beinhaltet diese Methode den Klasse SwingUtilities Methoden, um CoCode der durch den SwingWorker de von anderen Threads vom EDT ausführen ausgeführt werden soll. Wird nur ein zu lassen. Mal ausgeführt. static boolean isEventDispatchThread() Aufrufen gibt an ob der aktuelle Code auf dem void process(List¡V¿): Durch von publish(V) wird der Code von EDT ausgeführt wird process auf dem EDT ausgeführt. static void invokeLater(Runnable) die Auf diese Weise kann der SwingWorker run-Methode des Runnable-Objekts Zwischenergebnisse liefern. wird an die Warteschlange des EDT angehängt und später auf diesem T get(): Kann aufgerufen werden um die durch doInBackground() erzeugten ausgeführt. Daten zu erhalten. Falls diese noch static void invokeAndWait(Runnable) nicht verfügbar sind, wird die Threadähnlich wie invokeLater, allerdings ausführung gestoppt. get() kann eine wird der aufrufende Thread gestoppt InterruptedException werfen falls der bis die run-Methode fertig ausgeführt Thread beim Warten unterbrochen wurde. wird, oder eine ExecutionException public c l a s s MyThread extends Thread { falls in doInBackground() ein Fehler aufgetreten ist. public void run ( ) { S w i n g U t i l i t i e s . invokeLater (new Runnable ( ) { public void run ( ) { doWorkOnEDT ( ) ; } });}} void done(): Ist der SwingWorker mit der Ausführung fertig, wird automatisch der Code von done auf dem EDT ausgeführt und so das Endergebnis verarbeitet. Um einem SwingWorker mitzuteilen, dass seine Ausführung abge9.2 SwingWorker brochen werden soll, sollte die Methode SwingWorker.cancel() verwendet Falls eine Swing-Anwendung eine zeitinwerden. tensive Operation durchführen muss, bei der auch Zwischenergebnisse produziert wer- Folgendes Beispiel zeigt einen SwingWorker, den und durch den EDT verarbeitet wer- der eine Reihe Bilder lädt und während des 9 Plattform Solaris, Linux with GTK+ 2.2 or later Ladens die Namen der Bilder anzeigt. Nachdem das Laden abgeschlossen ist, werden die Bilder auf der GUI angezeigt. Other Solaris, Linux public c l a s s MyWorker extends SwingWorker<Image [ ] , S t r i n g >{ private S t r i n g [ ] imgURL ; Windows public Image [ ] doInBackground ( ) { Image [ ] b i l d e r = new Image [ 1 0 0 ] ; f o r ( i n t i = 0 ; i < 1 0 0 ; ++i ) { bilder [ i ] = ladeBild ( imgURL [ i ] ) ; p u b l i s h (imgURL [ i ] ) ; } return b i l d e r ; } @Override public void p r o c e s s ( L i s t <S t r i n g > namen ) { zeigeNamenAn ( namen . g e t ( 0 ) ) ; } @Override public void done ( ) { try { f ü g e B i l d e r E i n ( t h i s . g e t ( ) ) ; } catch ( I n t e r r u p t e d E x c e p t i o n e ) {} catch ( E x e c u t i o n E x c e p t i o n e ) {} } } Java Look-and-Feel com.sun.java.swing. plaf.gtk. GTKLookAndFeel com.sun.java.swing. plaf.motif. MotifLookAndFeel com.sun.java.swing. plaf.windows. WindowsLookAndFeel javax.swing. plaf.metal. MetalLookAndFeel Der Wechsel des aktuellen Look-and-Feel ist zur Laufzeit möglich. Dazu bietet die Klasse UIManager folgende statische Methoden: static void setLookAndFeel(String className): setzt den neuen Look-and-Feel. static String getSystemLookAndFeelClassName(): gibt den Namen des zum aktuellen System passenden Look-and-Feel als String zurück. static String getCrossPlatformLookAndFeelClassNam gibt den Namen des Standard-Lookand-Feel (Metal) als String zurück. Damit alle Komponenten den neuen Look-and-Feel annehmen, müssen sie mit der statischen Methode updateComponentTreeUI(Container) der Klasse SwingUtilities aktualisiert werden, wobei der aktuelle Top-Level-Container als Argument übergeben wird. 10 Look-and-Feel try { Das Aussehen der Komponenten wird durch UIManager . setLookAndFeel ( UIManager . getCrossPlatform den aktuellen Look-and-Feel bestimmt. Um LookAndFeelClassName ( ) ) ; Benutzern mit verschiedenen BetriebssysteSwingUtilities . updateComponentTreeUI ( t h i s ) ; men ihr gewohntes Erscheinungsbild zu bie} ten, stellt Swing neben dem Java-Standard catch ( E x c e p t i o n e r ) { System . e r r . p r i n t l n ( e ) ; } (Metal) auch Look-and-Feels für Windows, Linux und Mac zur Verfügung.[2] Themen 10 Themen wurden eingeführt, um schnell und einfach die Farben und Schriftarten des Metal-Look-and-Feels ändern zu können. Neben den mitgelieferten Ocean und DefaultMetalTheme lassen sich auch eigene Themen entwerfen. 12 Effekte Unter statischen Effekten versteht man nicht-animierte grafische Effekte, z.B. Unschärfe, Reflektionen oder Schatten, die aus verschiedenen Gründen verwendet Um das Thema zu ändern, bietet die werden können. Mit ihnen kann dem ErKlasse MetalLookAndFeel die Methode scheinungsbild der Anwendung der letzte Schliff verpasst werden.[7] setCurrentTheme(MetalTheme). Beispiel: Einfacher Unschärfeeffekt Um einen Unschärfeeffekt zu erzeugen benötigt man zuerst ein Kernel-Objekt, das das Gewicht der einzelnen Pixel angibt. 11 Double-Buffering Um bei grafischen Anwendungen eine kontinuierliche Bildfrequenz ohne Flackern und Artefakte zu gewährleisten, wird DoubleBuffering verwendet, bei dem der Bildspeicher in einen Front- und einen Backbuffer unterteilt wird. Der Frontbuffer dient dabei zur Ausgabe auf dem Bildschirm, während nur auf dem Backbuffer Änderungsoperationen durchgeführt werden. Zu passenden Zeitpunkten wird der Inhalt des Backbuffers in den Frontbuffer geladen und kann somit angezeigt werden. Diese Technik ermöglicht einen weicheren Bildaufbau und verhindert, dass unfertige Änderungen angezeigt werden.[7] public K e r n e l g e t K e r n e l ( i n t s i z e ) { f l o a t [ ] data = new f l o a t [ s i z e ∗ s i z e ] ; f o r ( i n t i = 0 ; i < data . l e n g t h ; ++i ) { data [ i ] = 1 . 0 f / ( s i z e ∗ s i z e ) ; } return new K e r n e l ( s i z e , s i z e , data ) ; } Aus diesem Kernel kann nun ConvolveOp-Objekt erzeugt werden. ein public ConvolveOp getConvolveOp ( K e r n e l k e r n ) { return new ConvolveOp ( kern , ConvolveOp . EDGE NO OP, n u l l ) ; } Mit diesem Objekt kann nun mit der statischen Methode filter der Klasse ConvolveOp ein unscharfes Bild erzeugt werden: B u f f e r e d I m a g e image = l a d e B i l d ( ) ; image = getConvolveOp ( g e t K e r n e l ( 3 ) ) . f i l t e r ( image , n u l l ) Swing bietet für alle Komponenten automatisches Double-Buffering, das mit setDoubleBuffered(boolean) aktiviert bzw. deaktiviert werden kann. Standardmäßig ist Double-Buffering aktiviert und für jedes Top-Level-Fenster ein Buffer verwendet. In diesem Buffer werden auch alle darunterliegenden Komponenten gerendert, ohne Rücksicht auf ihre Abb. 12: Originalbild und mit angewendeter Unschärfe Double-Buffering-Einstellungen. 11 Abb. 11: Einfach vs. Doppelpufferung 12 Aus diesem Grund besteht die Möglichkeit dynamische Effekte zu verwenden. Darunter versteht man Effekte, bei denen Zeit eine Rolle spielt, etwa Bewegungen, Auf- und Abblendeffekte oder pulsierende Hervorhebungen. Dynamische Effekte haben zwar mit der Funktionalität einer Anwendung nichts zu tun, können aber verwendet werden, um dem Benutzer das Arbeiten angenehmer zu gestalten.[7] zept, dass nur ein Thread für die Oberflächengestaltung genutzt wird, erfordert einige Einarbeitungszeit, um Anwendungen mit einer guten Performance zu schreiben. 15 Literatur [ 1 ] Java 6 API 2008 h t t p : / / j a v a . sun . com/ j a v a s e /6/ d o c s / a p i / [ 2 ] T r a i l : C r e a t i n g a GUI with JFC/ Swing 2008 h t t p : / / j a v a . sun . com/ d o c s / books / t u t o r i a l / u i s w i n g / i n d e x . html 13 Demoprojekt: JNiffel [ 3 ] P a i n t i n g i n AWT and Swing h t t p : / / j a v a . sun . com/ p r o d u c t s / j f c / t s c / a r t i c l e s / p a i n t i n g / Als Demoprojekt wurde ein Spiel als SwingAnwendung geschrieben, das ähnlich wie das bekannte Würfelspiel ’Kniffel’ gespielt wird. Zur Repräsentation der Würfel wurde eine neue Komponente implementiert, die sich von JButton ableitet und durch Überschreiben der paint-Methode je nach Status ein anderes Bild anzeigt. [ 4 ] O b e r f l ä c h e n p r o g r a m m i e r u n g h t t p : / /www. dpunkt . de / j a v a / P r o g r a m m i e r e n m i t J a v a / O b e r f l a e c h e n p r o g r a m m i e r u n g / 1 . html [ 5 ] Dr . S a t y a r a j Pantham Pure JFC Swing SAMS, 1999 [ 6 ] David Geary Graphic Java 2 , Volume 2 , Swing ( 3 rd E d i t i o n ) Sun M i c o r s y s t e m s P r e s s , 1999 Ein Menü ermöglicht es den aktuellen Lookand-Feel zur Laufzeit zu ändern, wobei das Angebot an Look-and-Feels dynamisch erzeugt wird, indem die auf dem System installierten Look-and-Feels abgefragt werden. 14 Fazit Abschließend lässt sich sagen, dass Java mit Swing ein sehr mächtiges Werkzeug zur Oberflächenprogrammierung bietet. Vor allem bei Verwendung eines GUI-Builders, wie ihn etwa NetBeans enthält, kann schnell eine Oberfläche entworfen werden. Bei größeren Anwendungen steigt die Schwierigkeit doch sehr stark an, da die Komponenten sehr komplex werden können. Auch das Kon- 13 [ 7 ] Chet Haase , Romain Guy F i l t h y Rich C l i e n t s P r e n t i c e H a l l , 2007