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