Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage |
<< | < | > | >> | API | Kapitel 37 - Swing: Container und Menüs |
Viele der Swing-Komponenten sind direkt oder indirekt aus der Klasse JComponent abgeleitet. Sie stellt eine Reihe allgemeiner Hilfsmittel zur Verfügung, die für daraus abgeleitete Komponentenklassen nützlich sind. Als Ableitung von java.awt.Container (und damit von java.awt.Component) besitzt JComponent bereits einen Großteil der Funktionalität von AWT-Komponenten. Insbesondere bietet sie als Container die Möglichkeit, andere Komponenten aufzunehmen, und sie kann einen Layout-Manager besitzen, der für die Größe und Anordnung der enthaltenen Komponenten zuständig ist.
Die mit dem AWT eingeführte grundsätzliche Unterscheidung zwischen elementaren Dialogelementen und solchen, die Unterkomponenten aufnehmen können, wurde mit der Einführung von Swing also weitgehend fallengelassen. In der Praxis ist das jedoch nur selten bedeutsam. Ein JButton beispielsweise stellt sich im praktischen Gebrauch stets als elementare Komponente dar - obwohl er als Konkretisierung von JComponent auch Unterkomponenten enthalten könnte.
Eine der auffälligeren Konsequenzen besteht darin, dass es in Swing keine zu Canvas korrespondierende Klasse gibt (siehe Kapitel 33). Elementare Dialogelemente mit selbst definierter Oberfläche werden in Swing direkt aus JComponent abgeleitet. |
|
JComponent bietet die Möglichkeit, ihren Instanzen eine Umrandung zu geben. Dazu gibt es die Methode setBorder, mit der der Komponente ein Objekt des Typs Border zugewiesen werden kann:
public void setBorder(Border border) |
javax.swing.JComponent |
Border ist ein Interface, zu dem es verschiedene Implementierungen gibt. Die wichtigsten von ihnen zeigt folgende Tabelle:
Klassenname | Beschreibung |
EmptyBorder | Unsichtbarer Rand mit einstellbarer Dicke |
LineBorder | Einfache Linie mit einstellbarer Farbe und Dicke |
BevelBorder | Erhabener oder vertiefter 3D-Effekt |
EtchedBorder | Eingelassene Linie mit 3D-Effekt |
CompoundBorder | Aus zwei anderen Umrandungen zusammengesetzt |
TitledBorder | Umrandung mit einem eingebetteten Text |
Tabelle 37.4: Border-Implementierungen
Die Klassen besitzen sehr unterschiedliche Konstruktoren, mit denen ihre jeweiligen Eigenschaften festgelegt werden. Obwohl die Border-Instanzen einfach mit new erzeugt werden könnten, bietet die Klasse BorderFactory im Paket javax.swing eine bessere Möglichkeit, dies zu tun. Zu jeder Art von Umrandung steht nämlich eine Factory-Methode zur Verfügung (createEmptyBorder, createLineBorder usw.), mit der ein Border-Objekt dieses Typs erzeugt werden kann. Wann immer möglich, versucht die BorderFactory dabei, Verweise auf bereits erzeugte Instanzen zurückzugeben. Da Umrandungen in GUI-Programmen sehr häufig benötigt werden, reduziert sich dadurch bei konsequenter Verwendung die Anzahl der kurzlebigen Objekte und die Belastung des Garbage Collectors.
Abbildung 37.11 zeigt ein Beispielprogramm, das sechs Labels mit unterschiedlichen Umrandungen enthält:
Abbildung 37.11: Die wichtigsten Umrandungen
JComponent bietet eine einfach anzuwendende Möglichkeit, Komponenten einen Tooltip-Text zuzuweisen. Dieser wird angezeigt, wenn die Maus über das Dialogelement bewegt und dort gehalten wird. Ein Tooltip gibt dem unerfahrenen Anwender Informationen zur Bedeutung und Funktion des ausgewählten Dialogelements. Tooltip-Texte werden mit der Methode setToolTipText zugewiesen; und mit getToolTipText können sie abgefragt werden:
public void setToolTipText(String text) public String getToolTipText() |
javax.swing.JComponent |
Tooltips können nicht nur einfache Texte enthalten, sondern prinzipiell beliebig komplex aufgebaut sein. Sie werden durch die aus JComponent abgleitete Klasse JToolTip repräsentiert. Aus ihr können anwendungsspezifische Tooltip-Klassen abgeleitet werden, die nahezu beliebige GUI-Funktionalitäten zur Verfügung stellen. Um einer Komponente einen solchen Tooltip zuzuordnen, muss die Methode createToolTip von JComponent überlagert werden und auf Anfrage ihr eigenes JToolTip-Objekt zurückgeben. |
|
Normalerweise braucht eine GUI-Anwendung sich um die konkrete Darstellung ihrer Dialogelemente keine Gedanken zu machen. Die elementaren Komponenten erledigen dies selbst und die zusammengesetzten Komponenten bedienen sich ihrer Layoutmanager und der Ausgabemethoden der elementaren Komponenten. Dies ändert sich, wenn eine eigene Komponente entwickelt werden soll. Bei AWT-Anwendungen wurde diese aus Canvas abgeleitet und in überlagerten Varianten von paint oder update wurde die nötige Bildschirmausgabe zur Verfügung gestellt.
In elementaren Swing-Komponenten, die aus JComponent abgeleitet wurden, liegen die Dinge etwas komplizierter. Die Methode paint hat bereits in JComponent eine recht aufwändige Implementierung und wird normalerweise nicht mehr überlagert. Im Prinzip ruft sie nacheinander ihre Methoden paintComponent, paintBorder und paintChildren auf. Die letzten beiden sind für das Zeichnen der Umrandung und der enthaltenen Dialogelemente zuständig und brauchen normalerweise in eigenen Komponenten nicht überlagert zu werden. Für die Darstellung der eigenen Komponente ist dagegen paintComponent zuständig:
protected void paintComponent(Graphics g) |
javax.swing.JComponent |
In JComponent wird jeder Aufruf von paintComponent an das ComponentUI der Komponente delegiert. Instanzen dieser im Paket javax.swing.plaf liegenden Klasse spielen in dem von jeder Swing-Komponente implementierten Model-View-Controller-Konzept die Rolle des Views, sind also für die grafische Darstellung der Komponente zuständig. Jede Swing-Komponente besitzt ein ComponentUI, das je nach Look-and-Feel unterschiedlich sein kann. Eine selbst definierte Komponente muss also entweder für jedes unterstützte Look-and-Feel ein passendes ComponentUI zur Verfügung stellen oder die Bildschirmdarstellung durch Überlagern von paintComponent selbst erledigen.
Eine interessante Hilfe zum Testen eigener Komponenten kann durch Aufruf der Methode setDebugGraphicsOptions aktiviert werden:
public void setDebugGraphicsOptions(int debugOptions) |
javax.swing.JComponent |
Dadurch wird die Komponente mit Hilfe eines DebugGraphics-Objekts gezeichnet. Es ist in der Lage, die verwendeten Grafikoperationen auf der Konsole zu protokollieren oder zur besseren Kontrolle verzögert auszugeben. Als Argument kann an setDebugGraphicsOptions eine der folgenden Konstanten aus der Klasse DebugGraphics übergeben werden:
Konstante | Bedeutung |
NONE_OPTION | Normale Ausgabe |
LOG_OPTION | Die Grafikoperationen werden auf der Console protokolliert. |
FLASH_OPTION | Die Grafikoperationen erfolgen verzögert und werden während der Ausgabe blinkend dargestellt. Bei dieser Option muss die Doppelpufferung für die Komponente ausgeschaltet werden. |
BUFFERED_OPTION | Gepufferte Ausgaben werden in einem separaten Frame angezeigt. |
Tabelle 37.5: DebugGraphics-Konstanten
Das folgende Programm zeigt eine einfache Anwendung der Debug-Grafik zur Darstellung eines Buttons. Mit Hilfe der statischen Methoden setFlashTime und setFlashCount der Klasse DebugGraphics wird die Blinkrate und -dauer angepasst:
001 /* Listing3711.java */ 002 003 import java.awt.*; 004 import javax.swing.*; 005 006 public class Listing3711 007 extends JFrame 008 { 009 public Listing3711() 010 { 011 super("Debug-Grafik"); 012 addWindowListener(new WindowClosingAdapter(true)); 013 Container cp = getContentPane(); 014 DebugGraphics.setFlashTime(100); 015 DebugGraphics.setFlashCount(3); 016 JButton button = new JButton("DEBUG-Button"); 017 RepaintManager repaintManager = RepaintManager.currentManager(button); 018 repaintManager.setDoubleBufferingEnabled(false); 019 button.setDebugGraphicsOptions(DebugGraphics.FLASH_OPTION); 020 cp.add(button); 021 } 022 023 public static void main(String[] args) 024 { 025 Listing3711 frame = new Listing3711(); 026 frame.setLocation(100, 100); 027 frame.setSize(300, 200); 028 frame.setVisible(true); 029 } 030 } |
Listing3711.java |
Anders als im AWT, bei dem alle Dialogelemente einen undurchsichtigen Hintergrund hatten, kann dieser bei Swing-Komponenten auch transparent sein. Damit lassen sich runde Buttons, Beschriftungen mit durchscheinendem Hintergrund oder ähnliche Effekte realisieren. Um den Hintergrund einer Komponente transparent zu machen, ist die Methode setOpaque aufzurufen und false zu übergeben. Standardmäßig ist der Hintergrund undurchsichtig. Das folgende Programm besitzt zwei Buttons, von denen der eine einen transparenten und der andere einen undurchsichtigen Hintergrund hat. Um den Unterschied besser erkennen zu können, befinden sie sich auf einer Komponente, die vollständig mit Gitterlinien bedeckt ist.
001 /* Listing3712.java */ 002 003 import java.awt.*; 004 import javax.swing.*; 005 006 public class Listing3712 007 extends JFrame 008 { 009 public Listing3712() 010 { 011 super("Transparenz"); 012 addWindowListener(new WindowClosingAdapter(true)); 013 Container cp = getContentPane(); 014 //SimpleGridComponent erzeugen 015 SimpleGridComponent grid = new SimpleGridComponent(); 016 grid.setLayout(new FlowLayout(FlowLayout.CENTER)); 017 //Transparenten Button hinzufügen 018 JButton button = new JButton("Transparent"); 019 button.setOpaque(false); 020 grid.add(button); 021 //Undurchsichtigen Button hinzufügen 022 button = new JButton("Opaque"); 023 grid.add(button); 024 //SimpleGridComponent hinzufügen 025 cp.add(grid, BorderLayout.CENTER); 026 } 027 028 public static void main(String[] args) 029 { 030 try { 031 String plaf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"; 032 UIManager.setLookAndFeel(plaf); 033 Listing3712 frame = new Listing3712(); 034 frame.setLocation(100, 100); 035 frame.setSize(300, 100); 036 frame.setVisible(true); 037 } catch (Exception e) { 038 e.printStackTrace(); 039 System.exit(1); 040 } 041 } 042 } 043 044 class SimpleGridComponent 045 extends JComponent 046 { 047 protected void paintComponent(Graphics g) 048 { 049 int width = getSize().width; 050 int height = getSize().height; 051 g.setColor(Color.gray); 052 for (int i = 0; i < width; i += 10) { 053 g.drawLine(i, 0, i, height); 054 } 055 for (int i = 0; i < height; i += 10) { 056 g.drawLine(0, i, width, i); 057 } 058 } 059 } |
Listing3712.java |
Die Ausgabe des Programms sieht so aus:
Abbildung 37.12: Ein Programm mit einem transparenten Button
Um bei animierten Komponenten das Bildschirmflackern zu vermeiden, kann die Technik des Doppelpufferns angewendet werden. Wir haben das für AWT-Komponenten in Abschnitt 34.2.4 ausführlich erklärt. Swing-Komponenten, die aus JComponent abgeleitet sind, können automatisch doppelgepuffert werden. Dazu ist lediglich ein Aufruf von setDoubleBuffered mit Übergabe von true erforderlich. Mit isDoubleBuffered kann der aktuelle Zustand dieser Eigenschaft abgefragt werden:
public void setDoubleBuffered(boolean aFlag) public boolean isDoubleBuffered() |
javax.swing.JComponent |
Bereits in der Klasse Component sind die Methoden getMinimumSize, getPreferredSize und getMaximumSize definiert. Sie werden in abgeleiteten Klassen überlagert, um dem Layoutmanager die minimale, optimale und maximale Größe der Komponenten mitzuteilen (siehe z.B. Abschnitt 33.2.2). In JComponent gibt es zusätzlich die Methoden setMinimumSize, setPreferredSize und setMaximumSize. Damit können die Größenvorgaben bestehender Komponenten verändert werden, ohne eine neue Klasse daraus ableiten zu müssen.
Sowohl in Swing- als auch in AWT-Programmen kann der Aufbau eines Dialogs geändert werden, wenn er bereits auf dem Bildschirm sichtbar ist. Dialogelemente können hinzugefügt oder entfernt oder in ihrem Aussehen geändert werden. Die dadurch implizierten Layoutänderungen werden zwar oft, aber nicht immer automatisch erkannt und es kann sein, dass die Bildschirmdarstellung die Änderungen nicht angemessen wiedergibt.
Wird beispielsweise die Beschriftung oder der Font eines Swing-Buttons verändert, so wird seine Größe den neuen Erfordernissen angepasst und der Dialog neu aufgebaut. Bei AWT-Buttons ist das nicht der Fall. Wenn sich der Platzbedarf für die Beschriftung ändert, ist der Button nach der Änderung entweder zu klein oder zu groß. Auch wenn neue Dialogelemente hinzugefügt werden, sind diese weder im AWT noch in Swing unmittelbar sichtbar.
Um einem Container mitzuteilen, dass das Layout seiner Komponenten komplett neu aufgebaut werden soll, ist dessen validate-Methode aufzurufen:
public void validate() |
java.awt.Container |
Um einen unnötigen Neuaufbau des Bildschirms zu vermeiden, wird validate allerdings nur dann wirklich aktiv, wenn der Container, auf dem der Aufruf erfolgte, zuvor mit invalidate als ungültig deklariert wurde:
public void invalidate() |
java.awt.Component |
Wird invalidate auf einer elementaren Komponente aufgerufen, die in einen Container eingebettet ist, wird der Aufruf an den Container weitergegeben und invalidiert auch diesen. Soll also nach der Änderung einer Komponente der zugehörige Container neu dargestellt werden, ist auf der Komponente invalidate und anschließend auf dem Container validate aufzurufen. In JComponent gibt es zusätzlich die Methode revalidate, die beide Schritte nacheinander durchführt.
Innerhalb eines Dialogs kann immer nur eine Komponente zur Zeit den Fokus haben, also Maus- und Tastaturereignisse erhalten. Durch Anklicken mit der Maus kann dieser direkt einer bestimmten Komponente zugewiesen werden. Alternativ kann (meist mit Hilfe der Tasten [TAB] und [UMSCHALT]+[TAB]) der Fokus auch per Tastendruck verändert werden. Die Komponenten eines Dialogs durchlaufen dabei einen Zyklus, der sich an der Einfüge-Reihenfolge der Elemente orientiert. Das zuerst mit add hinzugefügte Element enthält nach dem Aufrufen des Dialogs den Fokus zuerst.
Mitunter ist es sinnvoll, lokale Fokuszyklen zu bilden, um Gruppen von Komponenten zusammenzufassen und einfacher bedienen zu können. Mit dem JDK 1.4 wurde das Fokus-Subsystem vollständig neu geschrieben. Hauptziel dieser Änderung war es, eine große Zahl von existierenden Fehlern zu beheben sowie ein wohldefiniertes und plattformunabhängiges Fokusverhalten zu implementieren.
Für das Bilden von lokalen oder vom Standard abweichenden Fokuszyklen gibt es die abstrakte Klasse FocusTraversalPolicy im Paket java.awt. Sie bietet folgende Schnittstellen:
public Component getComponentAfter(Container con, Component com) public Component getComponentBefore(Container con, Component com) public Component getFirstComponent(Container con) public Component getLastComponent(Container con) public Component getDefaultComponent(Container con) |
java.awt.FocusTraversalPolicy |
Jede GUI-Komponente vom Typ Container kann die Wurzel eines Fokuszyklus sein. Dazu ist die Methode setFocusCycleRoot mit true als Parameter aufzurufen und anschließend an der Methode setFocusTraversalPolicy die konkrete FocusTraversalPolicy-Implementation zu setzen.
Das JDK bringt eine Reihe von konkreten Implementationen der FocusTraversalPolicy mit, zum Beispiel LayoutFocusTraversalPolicy, die Default-Policy in Swing-Applikationen.
Das Listing 37.13 verdeutlicht die Anwendung eines eigenen Fokuszyklus. Auf einem Panel liegen vier Buttons, deren Fokusreihenfolge jedes Mal per Zufallsgenerator neu bestimmt wird, wenn der Button »Mischen!« gedrückt wird.
Dazu repräsentiert die Liste buttons die aktuelle Reihenfolge der Elemente. Bei jedem [TAB]-Tastendruck wird der Index des Buttons in der Liste bestimmt, der den Fokus besitzt, und der rechts davon liegende Button wird herausgegeben. Durch die Verwendung des Modulo-Operators in der Methode getComponentAfter geben wir den ersten Button aus der Liste zurück, wenn der aktuelle Button der letzte in der definierten Reihenfolge ist. Dadurch ergibt sich ein Zyklus. Die Methode getComponentBefore ist analog implementiert. Zudem wurde die Methode getFirstComponent und getLastComponent überschrieben. Sie geben das erste Element bzw. das letzte Element in der Liste zurück.
getDefaultComponent liefert ebenfalls das erste Element in der Liste und damit den gleichen Button wie getFirstComponent. Der Unterschied besteht darin, dass beim Eintritt in den Fokuszyklus das Element den Fokus erhält, das durch getDefaultComponent bestimmt wird. getFirstComponent liefert dagegen das auf das letzte Element folgende.
001 /* Listing3713.java */ 002 003 import java.awt.*; 004 import java.awt.event.*; 005 import java.util.*; 006 import java.util.List; 007 import javax.swing.*; 008 009 class ZufallFocusTraversalPolicy 010 extends FocusTraversalPolicy 011 { 012 private List<JButton> buttons; 013 014 ZufallFocusTraversalPolicy(List<JButton> buttons) 015 { 016 this.buttons = new ArrayList<JButton>(buttons); 017 mischen(); 018 } 019 020 public Component getComponentAfter(Container con, Component com) 021 { 022 return buttons.get((buttons.indexOf(com)+1) % buttons.size()); 023 } 024 025 public Component getComponentBefore(Container con, Component com) 026 { 027 int n = buttons.size(); 028 return buttons.get((buttons.indexOf(com) + n-1) % n); 029 } 030 031 public Component getFirstComponent(Container con) 032 { 033 return buttons.get(0); 034 } 035 036 public Component getLastComponent(Container con) 037 { 038 return buttons.get(buttons.size()-1); 039 } 040 041 public Component getDefaultComponent(Container con) 042 { 043 return getFirstComponent(con); 044 } 045 046 public void mischen() 047 { 048 Collections.shuffle(buttons); 049 System.err.print("Fokusreihenfolge: "); 050 for (JButton button : buttons) { 051 System.err.print(button.getText() + " "); 052 } 053 System.err.println(); 054 } 055 } 056 057 public class Listing3713 058 extends JFrame 059 { 060 Listing3713() 061 { 062 setLayout(new FlowLayout()); 063 064 JPanel panel = new JPanel(); 065 List<JButton> buttons = new ArrayList<JButton>(); 066 for (int i = 1; i <= 4; i++) { 067 JButton button = new JButton(Integer.toString(i)); 068 panel.add(button); 069 buttons.add(button); 070 } 071 072 final ZufallFocusTraversalPolicy policy = 073 new ZufallFocusTraversalPolicy(buttons); 074 panel.setFocusCycleRoot(true); 075 panel.setFocusTraversalPolicy(policy); 076 077 JButton mischen = new JButton("Mischen!"); 078 mischen.addActionListener(new ActionListener() 079 { 080 public void actionPerformed(ActionEvent e) 081 { 082 policy.mischen(); 083 } 084 }); 085 086 add(panel); 087 add(mischen); 088 pack(); 089 } 090 091 public static void main(String[] args) 092 { 093 Listing3713 frame = new Listing3713(); 094 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 095 frame.setVisible(true); 096 } 097 } |
Listing3713.java |
Die Ausgabe des Programms ist zum Beispiel:
Fokusreihenfolge: 2 4 1 3
Fokusreihenfolge: 3 2 1 4
Fokusreihenfolge: 2 1 3 4
Abbildung 37.13: Buttonpanel mit eigener FocusTraversalPolicy
Das Listing 37.13 verwendet statt des WindowClosingAdapter die Option JFrame.EXIT_ON_CLOSE. Dadurch wird der JFrame beim Klick auf das Kreuz geschlossen, ohne dass ein expliziter WindowListener registriert werden muss. |
|
Als letzte Eigenschaft der Klasse JComponent wollen wir uns das Registrieren von Tastaturkommandos ansehen. Dabei wird eine bestimmte Tastenkombination bei einer Komponente angemeldet und löst bei jeder Anwendung ein Action-Event aus. Tastaturkommandos können sowohl bei elementaren Komponenten als auch bei Containern angemeldet werden, und es gibt verschiedene Möglichkeiten, sie vom Fokus der Komponente abhängig zu machen. Das Registrieren erfolgt mit der Methode registerKeyboardAction:
public void registerKeyboardAction( ActionListener anAction, String aCommand, KeyStroke aKeyStroke, int aCondition ) |
javax.swing.JComponent |
Deren erstes Argument ist der ActionListener, der im Fall des Tastendrucks (mit dem Kommando aCommand) aufgerufen werden soll. aKeyStroke definiert die zu registrierende Tastenkombination (wie man KeyStroke-Objekte erzeugt, wurde in Listing 37.8 gezeigt). Das letzte Argument gibt an, in welcher Relation der Fokus zur Komponente stehen muss, damit das Kommando aktiv wird. Er kann einen der folgenden Werte annehmen:
Konstante | Bedeutung |
WHEN_FOCUSED | Das Tastaturkommando wird nur ausgelöst, wenn die Komponente den Fokus hat. |
WHEN_IN_FOCUSED_WINDOW | Das Tastaturkommando wird ausgelöst, wenn die Komponente den Fokus hat oder wenn sie zu einem Container gehört, der gerade den Fokus hat. |
WHEN_ANCESTOR_OF_FOCUSED_COMPONENT | Das Tastaturkommando wird ausgelöst, wenn die Komponente oder eines der darin enthaltenen Elemente den Fokus hat. |
Tabelle 37.6: Bedingungen zur Registrierung von Tastaturkommandos
Bei der Verwendung der zweiten und dritten Variante werden die Tastendrücke immer dann ausgeführt, wenn der Container selbst oder eine der darin enthaltenen Komponenten den Fokus hat. Der Unterschied besteht in der Sichtweise. WHEN_IN_FOCUSED_WINDOW wird auf die elementaren Komponenten angewendet, während WHEN_ANCESTOR_OF_FOCUSED_COMPONENT für den Container selbst vorgesehen ist.
Das folgende Programm zeigt eine beispielhafte Anwendung für das Registrieren von Tastaturkommandos:
001 /* Listing3714.java */ 002 003 import java.awt.*; 004 import java.awt.event.*; 005 import javax.swing.*; 006 import javax.swing.border.*; 007 008 public class Listing3714 009 extends JFrame 010 implements ActionListener 011 { 012 public Listing3714() 013 { 014 super("Invalidierung"); 015 addWindowListener(new WindowClosingAdapter(true)); 016 Container cp = getContentPane(); 017 ((JComponent)cp).setBorder(new EmptyBorder(5, 5, 5, 5)); 018 cp.setLayout(new FlowLayout()); 019 //Textfelder erzeugen 020 JTextField tf1 = new JTextField("Zeile1", 20); 021 JTextField tf2 = new JTextField("Zeile2", 20); 022 JTextField tf3 = new JTextField("Zeile3", 20); 023 //STRG+UMSCHALT+F6 auf Frame registrieren 024 ((JComponent)cp).registerKeyboardAction( 025 this, 026 "dialog", 027 ctrlShift(KeyEvent.VK_F6), 028 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT 029 ); 030 //STRG+UMSCHALT+F7 auf tf1 registrieren 031 tf1.registerKeyboardAction( 032 this, 033 "tf1", 034 ctrlShift(KeyEvent.VK_F7), 035 JComponent.WHEN_IN_FOCUSED_WINDOW 036 ); 037 //STRG+UMSCHALT+F8 auf tf2 registrieren 038 tf2.registerKeyboardAction( 039 this, 040 "tf2", 041 ctrlShift(KeyEvent.VK_F8), 042 JComponent.WHEN_FOCUSED 043 ); 044 //Textfelder hinzufügen 045 cp.add(tf1); 046 cp.add(tf2); 047 cp.add(tf3); 048 } 049 050 public void actionPerformed(ActionEvent event) 051 { 052 String cmd = event.getActionCommand(); 053 System.out.println(cmd); 054 } 055 056 private KeyStroke ctrlShift(int vkey) 057 { 058 return KeyStroke.getKeyStroke( 059 vkey, 060 Event.SHIFT_MASK + Event.CTRL_MASK 061 ); 062 } 063 064 public static void main(String[] args) 065 { 066 Listing3714 frame = new Listing3714(); 067 frame.setLocation(100, 100); 068 frame.setSize(300, 200); 069 frame.setVisible(true); 070 } 071 } |
Listing3714.java |
Das Hauptfenster selbst registriert die Tastenkombination [STRG]+[UMSCHALT]+[F6]. Sie funktioniert unabhängig davon, welches der drei Textfelder den Fokus hat. Das oberste Textfeld registriert [STRG]+[UMSCHALT]+[F7] mit der Bedingung WHEN_IN_FOCUSED_WINDOW. Die Tastenkombination steht in diesem Dialog also ebenfalls immer zur Verfügung. Das nächste Textfeld registriert [STRG]+[UMSCHALT]+[F8], lässt sie allerdings nur zu, wenn es selbst den Fokus hat.
JPanel ist die Basisklasse für GUI-Container in Swing, die nicht Hauptfenster sind. Sie ist direkt aus JComponent abgeleitet und fügt dieser nur wenig hinzu. Wichtigstes Unterscheidungsmerkmal ist die Tatsache, dass einem JPanel standardmäßig ein FlowLayout als Layoutmanager zugeordnet ist. Instanzen von JComponent besitzen dagegen zunächst keinen Layoutmanager. JPanel definiert die folgenden Konstruktoren:
public JPanel() public JPanel(boolean isDoubleBuffered) public JPanel(LayoutManager layout) public JPanel(LayoutManager layout, boolean isDoubleBuffered) |
javax.swing.JPanel |
Der parameterlose Konstruktor erzeugt ein JPanel mit Doppelpufferung und einem FlowLayout. Wahlweise können beide Eigenschaften durch Setzen der Argumente isDoubleBuffered und layout geändert werden. In der weiteren Anwendung ist JPanel mit JComponent identisch.
Eine weitere Container-Klasse, die direkt aus JComponent abgeleitet wurde, ist JLayeredPane. Sie fügt den Dialogen eine dritte Dimension hinzu und ermöglicht mit Hilfe eines Layerkonzepts die kontrollierte Anordnung von Komponenten übereinander. JLayeredPane ist Vaterklasse von JDesktopPane (siehe Abschnitt 37.1.6) und wichtiger Bestandteil der Struktur von Hauptfenstern (siehe Abschnitt 37.1.1). In der praktischen Anwendung wird sie nur selten direkt gebraucht und wir wollen nicht weiter darauf eingehen.
Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage, Addison Wesley, Version 7.0 |
<< | < | > | >> | API | © 1998, 2011 Guido Krüger & Heiko Hansen, http://www.javabuch.de |