From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001 From: Sven Eisenhauer Date: Fri, 10 Nov 2023 15:11:48 +0100 Subject: add new repo --- .../hjp5/html/k100244.html | 928 +++++++++++++++++++++ 1 file changed, 928 insertions(+) create mode 100644 Master/Reference Architectures and Patterns/hjp5/html/k100244.html (limited to 'Master/Reference Architectures and Patterns/hjp5/html/k100244.html') diff --git a/Master/Reference Architectures and Patterns/hjp5/html/k100244.html b/Master/Reference Architectures and Patterns/hjp5/html/k100244.html new file mode 100644 index 0000000..a29c781 --- /dev/null +++ b/Master/Reference Architectures and Patterns/hjp5/html/k100244.html @@ -0,0 +1,928 @@ + + + +Handbuch der Java-Programmierung, 5. Auflage + + + + + + + + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage +
 <<  +  <   +  >   + >>  + API  +Kapitel 38 - Swing: Komponenten II +
+
+ + + + +

38.1 Spezielle Panels

+
+ +
+ + + + +

38.1.1 JScrollPane

+ +

+Die Klasse JScrollPane +wurde in den vorigen Abschnitten bereits mehrfach verwendet. In Verbindung +mit den Klassen JTextArea +und JList +bestand ihre Aufgabe darin, Dialogelemente, die zu groß für +den zur Verfügung stehenden Platz waren, mit Hilfe eines verschiebbaren +Fensters ausschnittsweise sichtbar zu machen. Dabei war es ausreichend, +das betreffende Dialogelement an den Konstruktor von JScrollPane +zu übergeben und anstelle des Dialogelements selbst die JScrollPane-Instanz +an den Container zu übergeben. + +

+JScrollPane +besitzt aber noch weitere Fähigkeiten, die hier kurz vorgestellt +werden sollen. Zunächst wollen wir uns ihre wichtigsten Konstruktoren +ansehen: +

+ + + + + +
+ +
+public JScrollPane(Component view)
+public JScrollPane(Component view, int vsbPolicy, int hsbPolicy)
+
+
+
+javax.swing.JScrollPane
+ +

+Die Argumente vsbPolicy und +hsbPolicy geben an, wann ein +horizontaler bzw. vertikaler Schieberegler eingeblendet wird. Hier +können folgende Werte angegeben werden: + +

+ + + + + + + + + + + + + + + + + + + + + + + +
KonstanteBedeutung
VERTICAL_SCROLLBAR_NEVERDer vertikale Schieberegler wird nie angezeigt.
VERTICAL_SCROLLBAR_ALWAYSDer vertikale Schieberegler wird immer angezeigt.
VERTICAL_SCROLLBAR_AS_NEEDEDDer vertikale Schieberegler wird nur angezeigt, +wenn er tatsächlich benötigt wird.
HORIZONTAL_SCROLLBAR_NEVERDer horizontale Schieberegler wird nie angezeigt.
HORIZONTAL_SCROLLBAR_ALWAYSDer horizontale Schieberegler wird immer +angezeigt.
HORIZONTAL_SCROLLBAR_AS_NEEDEDDer horizontale Schieberegler wird nur angezeigt, +wenn er tatsächlich benötigt wird.
+

+Tabelle 38.1: Anzeige der Schieberegler bei JScrollPane

+ +

+Wenn die Argumente vsbPolicy +und hsbPolicy nicht angegeben +werden, blendet JScrollPane +die Schieberegler nur dann ein, wenn sie wirklich benötigt werden +(wenn also das Dialogelement in der jeweiligen Ausdehnung größer +als der verfügbare Platz ist). + +

+Die beiden wichtigsten zusätzlichen Fähigkeiten von JScrollPane +bestehen darin, Spalten- und Zeilenheader anzeigen und die Eckelemente +mit beliebigen Komponenten belegen zu können (siehe Abbildung 38.1): +

+ + + + + +
+ +
+public void setColumnHeaderView(Component view)
+public void setRowHeaderView(Component view)
+
+public void setCorner(String key, Component corner)
+
+
+
+javax.swing.JScrollPane
+ +

+Mit setColumnHeaderView +kann eine Komponente für den Spaltenkopf angegeben werden. Sie +wird über dem eigentlichen Dialogelement angezeigt und bei horizontalen +Bewegungen zusammen mit diesem verschoben. Bei vertikalen Schieberbewegungen +bleibt sie dagegen an ihrem Platz. Analog dazu kann mit setRowHeaderView +ein Zeilenkopf angegeben werden, der links neben der eigentlichen +Komponente platziert wird. Er wird bei vertikalen Bewegungen verschoben +und behält bei horizontalen Bewegungen seinen Platz bei. + +

+Mit setCorner +kann in einer beliebigen der vier ungenutzten Ecken einer JScrollPane +ein Dialogelement platziert werden. Der Parameter key +gibt dabei an, welche Ecke belegt werden soll. Als Argument kann eine +der Konstanten LOWER_LEFT_CORNER, +LOWER_RIGHT_CORNER , +UPPER_LEFT_CORNER +oder UPPER_RIGHT_CORNER +der Klasse JScrollPane +angegeben werden. +

+ + + + + + + + + +
+ +

+Zu beachten ist allerdings, dass die Eckflächen unter Umständen +gar nicht zur Verfügung stehen. Die beiden Ecken auf der linken +Seite sind beispielsweise nur dann vorhanden, wenn ein Zeilenkopf +eingeblendet wurde. Die rechte obere ist nur vorhanden, wenn ein vertikaler +Schieberegler eingeblendet wurde, und die rechte untere erfordert +sogar die Anwesenheit beider Schieberegler. Auch kann die Anwendung +praktisch keinen Einfluss auf die Größe der Ecken nehmen. +Diese wird ausschließlich durch die Ausdehnung der Schieberegler +und des Zeilenkopfes bestimmt. Summa sumarum ist die Möglichkeit, +die Ecken belegen zu können, eine nur in Ausnahmefällen +nützliche Eigenschaft.

+ + + + +
 Hinweis 
+
+

+ + +

+ +

+Abbildung 38.1: Die Anatomie einer JScrollPane

+ +

+Das folgende Beispiel zeigt ein Programm, in dem eine JScrollPane +ein zu großes JPanel +mit hundert Checkboxen aufnimmt. In den beiden rechten Ecken wird +jeweils ein JLabel +platziert, und als Spaltenkopf wird eine Instanz der Klasse ColumnHeader +verwendet: + + +

+ + + + + +
+ +
+001 /* Listing3801.java */
+002 
+003 import java.awt.*;
+004 import java.awt.event.*;
+005 import javax.swing.*;
+006 
+007 public class Listing3801
+008 extends JFrame
+009 {
+010   public Listing3801()
+011   {
+012     super("JScrollPane");
+013     addWindowListener(new WindowClosingAdapter(true));
+014     //Dialogpanel erzeugen
+015     JPanel panel = new JPanel();
+016     panel.setLayout(new GridLayout(10, 10));
+017     for (int i = 1; i <= 100; ++i) {
+018       panel.add(new JCheckBox("Frage " + i));
+019     }
+020     //JScrollPane erzeugen
+021     JScrollPane scroll = new JScrollPane(panel);
+022     scroll.setCorner(
+023       JScrollPane.UPPER_RIGHT_CORNER,
+024       new JLabel("1", JLabel.CENTER)
+025     );
+026     scroll.setCorner(
+027       JScrollPane.LOWER_RIGHT_CORNER,
+028       new JLabel("2", JLabel.CENTER)
+029     );
+030     scroll.setColumnHeaderView(new ColumnHeader(panel, 10));
+031     //JScrollPane zur ContentPane hinzufügen
+032     getContentPane().add(scroll, BorderLayout.CENTER);
+033   }
+034 
+035   public static void main(String[] args)
+036   {
+037     Listing3801 frame = new Listing3801();
+038     frame.setLocation(100, 100);
+039     frame.setSize(300, 150);
+040     frame.setVisible(true);
+041   }
+042 }
+043 
+044 class ColumnHeader
+045 extends JComponent
+046 {
+047   JComponent component;
+048   int        columns;
+049 
+050   public ColumnHeader(JComponent component, int columns)
+051   {
+052     this.component = component;
+053     this.columns   = columns;
+054   }
+055 
+056   public void paintComponent(Graphics g)
+057   {
+058     int width = component.getSize().width;
+059     int height = getSize().height;
+060     int colwid = width / columns;
+061     for (int i = 0; i < columns; ++i) {
+062       g.setColor(i % 2 == 0 ? Color.yellow : Color.gray);
+063       g.fillRect(i * colwid, 0, colwid, height);
+064     }
+065     g.setColor(Color.black);
+066     g.drawLine(0, height - 1, width, height - 1);
+067   }
+068 
+069   public Dimension getPreferredSize()
+070   {
+071     return new Dimension(component.getSize().width, 20);
+072   }
+073 }
+
+
+Listing3801.java
+ +Listing 38.1: Die Klasse JScrollPane

+ +

+Die Klasse ColumnHeader ist +aus JComponent +abgeleitet und wird als Spaltenkopf für die JPanel-Komponente +verwendet. Deren Spalten sind in diesem Sonderfall alle gleich breit. +Das Panel selbst und die Spaltenzahl werden an den Konstruktor übergeben, +und mit Hilfe dieser Angaben werden die nebeneinanderliegenden Spalten +als abwechselnd grau und gelb gefärbte Rechtecke angezeigt. Zusätzlich +wird eine schwarze Linie als untere Begrenzung des Spaltenkopfes gezeichnet. +Durch Überlagern von getPreferredSize +teilt ColumnHeader der JScrollPane +seine Größe mit. Die Breite entspricht dabei der Breite +der scrollbaren Komponente, die Höhe ist fest auf zwanzig Pixel +eingestellt. + +

+Die Ausgabe des Programms ist: +

+ + +

+ +

+Abbildung 38.2: Die Klasse JScrollPane

+ + + + +

38.1.2 JSplitPane

+ +

+JSplitPane +ist ein Panel, mit dem zwei Komponenten neben- oder übereinander +platziert werden können. Die Komponenten werden dabei durch einen +sichtbaren Separator voneinander getrennt. Der Anwender kann den Separator +verschieben und so den Platz, der beiden Komponenten zur Verfügung +steht, variieren. Ein JSplitPane +ist beispielsweise nützlich, wenn Komponenten dargestellt werden +sollen, deren Breite oder Höhe von den darin enthaltenen Daten +abhängig ist. Das Programm braucht dann den benötigten Platz +nur grob vorzugeben, und der Anwender kann durch Verschieben des Separators +zur Laufzeit festlegen, wieviel Platz er jeder Komponente zur Verfügung +stellen will. + +

+Die Konstruktoren von JSplitPane +sind: +

+ + + + + +
+ +
+public JSplitPane(int orientation)
+
+public JSplitPane(
+  int orientation,
+  boolean continuousLayout
+)
+
+public JSplitPane(
+  int orientation,
+  Component leftComponent,
+  Component rightComponent
+)
+
+public JSplitPane(
+  int orientation,
+  boolean continuousLayout,
+  Component leftComponent,
+  Component rightComponent
+)
+
+
+
+javax.swing.JSplitPane
+ +

+Der Parameter orientation gibt +an, wie die Elemente zueinander angeordnet werden sollen. Hat er den +Wert HORIZONTAL_SPLIT, +werden sie nebeneinander, bei VERTICAL_SPLIT +übereinander angeordnet. Hat continuousLayout +den Wert true, +so wird schon beim Verschieben des Separators der Bildschirminhalt +aktualisiert. Andernfalls erfolgt das erst nach Ende des Verschiebevorgangs. +In den Parametern leftComponent +und rightComponent werden die +beiden einzubettenden Komponenten übergeben. Alle Eigenschaften +können auch nach der Instanzierung verändert bzw. abgefragt +werden: +

+ + + + + +
+ +
+public void setOrientation(int orientation)
+public void setContinuousLayout(boolean continuousLayout)
+public void setLeftComponent(Component comp)
+public void setRightComponent(Component comp)
+public void setTopComponent(Component comp)
+public void setBottomComponent(Component comp)
+
+public int getOrientation()
+public boolean isContinuousLayout()
+public Component getLeftComponent()
+public Component getTopComponent()
+public Component getRightComponent()
+public Component getBottomComponent()
+
+
+
+javax.swing.JSplitPane
+ +

+Die Größe der beiden Komponenten richtet sich nach ihren +minimalen und gewünschten Abmessungen. JSplitPane +ermittelt diese Werte durch Aufruf von getPreferredSize +und getMinimumSize +auf den Komponentenobjekten. Es gilt: +

+

+ + + + + + + + + + + +
+ +

+Manche Komponenten liefern beim Aufruf von getMinimumSize +die Größe, die sie beim ersten Sichtbarwerden auf dem Bildschirm +hatten. In diesem Fall ist der Separator überhaupt nicht veränderbar, +denn jede Verschiebung würde die minimale Größe einer +der beiden Komponenten unterschreiten. Falls ein solches Problem auftritt, +kann Abhilfe geschaffen werden, indem durch Aufruf von setMinimumSize +die minimale Größe der Komponenten vermindert wird.

+ + + + +
 Tipp 
+
+ +

+Eine interessante Methode zur Modifikation des Separators ist setOneTouchExpandable: +

+ + + + + +
+ +
+public void setOneTouchExpandable(boolean newValue)
+
+
+
+javax.swing.JSplitPane
+ +

+Wird sie mit true +als Argument aufgerufen, erhält der Separator zwei kleine Pfeile, +die jeweils auf eine der beiden Komponenten zeigen. Wird einer von +ihnen angeklickt, so wird der Separator komplett auf die angezeigte +Seite verschoben. Die auf dieser Seite liegende Komponente wird verdeckt +und die andere erhält den vollen zur Verfügung stehenden +Platz (die von getMinimumSize +definierten Grenzen werden dabei ignoriert). Ein weiterer Klick auf +den Separator gibt der verdeckten Komponente wieder ihre Minimalgröße. + +

+Das folgende Programm zeigt einen JFrame +mit einem horizontal geteilten JSplitPane. +Als Komponenten werden zwei Instanzen der weiter unten definierten +Klasse GridComponent verwendet, +die ein Gitternetz anzeigt, dessen Maschengröße proportional +zur Ausdehnung der Komponente ist: + + +

+ + + + + +
+ +
+001 /* Listing3802.java */
+002 
+003 import java.awt.*;
+004 import java.awt.event.*;
+005 import javax.swing.*;
+006 
+007 public class Listing3802
+008 extends JFrame
+009 {
+010   public Listing3802()
+011   {
+012     super("JSplitPane");
+013     addWindowListener(new WindowClosingAdapter(true));
+014     //Linkes Element erzeugen
+015     GridComponent grid1 = new GridComponent();
+016     grid1.setMinimumSize(new Dimension(50, 100));
+017     grid1.setPreferredSize(new Dimension(180, 100));
+018     //Rechtes Element erzeugen
+019     GridComponent grid2 = new GridComponent();
+020     grid2.setMinimumSize(new Dimension(100, 100));
+021     grid2.setPreferredSize(new Dimension(80, 100));
+022     //JSplitPane erzeugen
+023     JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
+024     sp.setLeftComponent(grid1);
+025     sp.setRightComponent(grid2);
+026     sp.setOneTouchExpandable(true);
+027     sp.setContinuousLayout(true);
+028     getContentPane().add(sp, BorderLayout.CENTER);
+029   }
+030 
+031   public static void main(String[] args)
+032   {
+033     Listing3802 frame = new Listing3802();
+034     frame.setLocation(100, 100);
+035     frame.setSize(300, 200);
+036     frame.setVisible(true);
+037   }
+038 }
+039 
+040 class GridComponent
+041 extends JComponent
+042 {
+043   public void paintComponent(Graphics g)
+044   {
+045     g.setColor(Color.gray);
+046     int width = getSize().width;
+047     int height = getSize().height;
+048     for (int i = 0; i < 10; ++i) {
+049       g.drawLine(i * width / 10, 0, i * width / 10, height);
+050     }
+051     for (int i = 0; i < 10; ++i) {
+052       g.drawLine(0, i * height / 10, width, i * height / 10);
+053     }
+054     g.setColor(Color.black);
+055     g.drawString("" + width, 5, 15);
+056   }
+057 }
+
+
+Listing3802.java
+ +Listing 38.2: Die Klasse JSplitPane

+ +

+Die Ausgabe des Programms ist: +

+ + +

+ +

+Abbildung 38.3: Die Klasse JSplitPane

+ + + + +

38.1.3 JTabbedPane

+ +

+Als letztes der speziellen Panels wollen wir uns die Klasse JTabbedPane +ansehen. Mit ihr ist es möglich, Dialoge zu erstellen, die eine +Reihe von Registerkarten enthalten. Das sind Unterdialoge, die über +ein am Rand befindliches Register einzeln ausgewählt werden können. +Derartige Registerkarten werden beispielsweise in Konfigurationsdialogen +verwendet, wenn die zu bearbeitenden Optionen nicht alle auf eine +Seite passen. + +

+JTabbedPane +stellt zwei Konstruktoren zur Verfügung: +

+ + + + + +
+ +
+public JTabbedPane()
+public JTabbedPane(int tabPlacement)
+
+
+
+javax.swing.JTabbedPane
+ +

+Der erste von beiden erzeugt ein JTabbedPane +mit oben liegenden Registern. Beim zweiten kann explizit angegeben +werden, auf welcher Seite die Register angeordnet werden sollen. Hier +können die Konstanten TOP, +BOTTOM, +LEFT +oder RIGHT +aus dem Interface SwingConstants +übergeben werden. Üblich ist es, die Register links oder +oben anzuordnen. Mit den Methoden getTabPlacement +und setTabPlacement +kann auch nachträglich auf die Anordnung zugegriffen werden. + +

+Nach der Instanzierung ist der Registerdialog zunächst leer. +Um Registerkarten hinzuzufügen, kann eine der Methoden addTab +oder insertTab +aufgerufen werden: +

+ + + + + +
+ +
+public void addTab(
+  String title,
+  Icon icon,
+  Component component,
+  String tip
+)
+
+public void insertTab(
+  String title,
+  Icon icon,
+  Component component,
+  String tip,
+  int index
+)
+
+
+
+javax.swing.JTabbedPane
+ +

+Der Parameter title gibt die +Beschriftung des Registereintrags an. Mit icon +kann zusätzlich ein Icon und mit tip +ein Tooltiptext hinzugefügt werden. Der Parameter component +gibt das darzustellende Dialogelement an. Meist wird hier eine Containerklasse +übergeben (z.B. ein JPanel), +die den entsprechenden Unterdialog enthält. Die Parameter icon +und tip sind optional, d.h. +es gibt die beiden Methoden auch ohne sie. addTab +fügt die Registerkarte am Ende ein, bei insertTab +kann die Einfügeposition mit dem Parameter index +selbst angegeben werden. + +

+Bereits definierte Registerkarten können auch wieder entfernt +werden: +

+ + + + + +
+ +
+public void removeTabAt(int index)
+public void removeAll()
+
+
+
+javax.swing.JTabbedPane
+ +

+removeTabAt +entfernt die Karte mit dem angegebenen Index, removeAll +entfernt alle Karten. + +

+Mit getTabCount +kann die Anzahl der Registerkarten ermittelt werden, und mit getComponentAt +kann die Komponente einer beliebigen Registerkarte ermittelt werden. +Mit setComponentAt +kann der Inhalt einer Registerkarte sogar nachträglich ausgetauscht +werden: +

+ + + + + +
+ +
+public int getTabCount()
+
+public Component getComponentAt(int index)
+public void setComponentAt(int index, Component component)
+
+
+
+javax.swing.JTabbedPane
+ +

+In einem Registerdialog ist immer genau eine der Karten selektiert. +Mit getSelectedIndex +kann deren Index ermittelt werden, mit getSelectedComponent +sogar direkt auf ihren Inhalt zugegriffen werden. Die Methode setSelectedIndex +erlaubt es, programmgesteuert eine beliebige Registerkarte auszuwählen: +

+ + + + + +
+ +
+public int getSelectedIndex()
+public Component getSelectedComponent()
+
+public void setSelectedIndex(int index)
+
+
+
+javax.swing.JTabbedPane
+ +

+Registerkarten besitzen eine Reihe von Eigenschaften, die einzeln +verändert werden können. Die wichtigste von ihnen ist die +Möglichkeit, sie zu aktivieren oder zu deaktivieren. Nur aktivierte +Karten können ausgewählt werden, deaktivierte dagegen nicht. +Der Zugriff auf den Aktivierungsstatus erfolgt mit den Methoden setEnabledAt +und isEnabledAt: +

+ + + + + +
+ +
+public boolean isEnabledAt(int index)
+public void setEnabledAt(int index, boolean enabled)
+
+
+
+javax.swing.JTabbedPane
+

+ + + + + + + + + + + +
+ +

+Bei jeder Änderung der Selektion versendet ein JTabbedPane +ein ChangeEvent +an registrierte ChangeListener. +Auf diese Weise ist es möglich, Programmcode zu schreiben, der +beim Anwählen oder Verlassen einzelner Registerkarten ausgeführt +wird. Eine der Anwendungen hierfür besteht darin, die Dialoge +auf den Registerkarten erst dann zu erzeugen, wenn sie wirklich gebraucht +werden. Dazu wird an alle Registerkarten zunächst ein leeres +Panel übergeben und erst in der Methode stateChanged +durch den eigentlichen Dialog ersetzt. Auf diese Weise spart das Programm +beim Initialisieren des Registerdialogs Rechenzeit und Speicher, was +sich vor allem bei komplexen Dialogen positiv bemerkbar machen könnte.

+ + + + +
 Tipp 
+
+ +

+Das folgende Programm zeigt ein einfaches Beispiel eines Registerdialogs. +Es erstellt ein JTabbedPane +mit fünf Registerkarten, die jeweils ein JPanel +mit einem Label und einem Button enthalten. Das Label zeigt den Namen +der Karte an, der Button dient dazu, die jeweils nächste Karte +auszuwählen. Dessen Aktivität ist in der Klasse NextTabActionListener +gekapselt. Als Besonderheit wird nach jedem Seitenwechsel requestDefaultFocus +auf der neuen Seite aufgerufen, um automatisch dem ersten Dialogelement +den Fokus zu geben. + + +

+ + + + + +
+ +
+001 /* Listing3803.java */
+002 
+003 import java.awt.*;
+004 import java.awt.event.*;
+005 import javax.swing.*;
+006 
+007 public class Listing3803
+008 extends JFrame
+009 {
+010   JTabbedPane tp;
+011 
+012   public Listing3803()
+013   {
+014     super("JTabbedPane");
+015     addWindowListener(new WindowClosingAdapter(true));
+016     tp = new JTabbedPane();
+017     for (int i = 0; i < 5; ++i) {
+018       JPanel panel = new JPanel();
+019       panel.add(new JLabel("Karte " + i));
+020       JButton next = new JButton("Weiter");
+021       next.addActionListener(new NextTabActionListener());
+022       panel.add(next);
+023       tp.addTab("Tab" + i, panel);
+024     }
+025     getContentPane().add(tp, BorderLayout.CENTER);
+026   }
+027 
+028   class NextTabActionListener
+029   implements ActionListener
+030   {
+031     public void actionPerformed(ActionEvent event)
+032     {
+033       int tab = tp.getSelectedIndex();
+034       tab = (tab >= tp.getTabCount() - 1 ? 0 : tab + 1);
+035       tp.setSelectedIndex(tab);
+036       ((JPanel)tp.getSelectedComponent()).requestDefaultFocus();
+037     }
+038   }
+039 
+040   public static void main(String[] args)
+041   {
+042     Listing3803 frame = new Listing3803();
+043     frame.setLocation(100, 100);
+044     frame.setSize(300, 200);
+045     frame.setVisible(true);
+046   }
+047 }
+
+
+Listing3803.java
+ +Listing 38.3: Die Klasse JTabbedPane

+ +

+Die Ausgabe des Programms ist: +

+ + +

+ +

+Abbildung 38.4: Die Klasse JTabbedPane

+
+ + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 +
 <<  +  <   +  >   + >>  + API  +© 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de +
+ + + -- cgit v1.2.3