Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage |
<< | < | > | >> | API | Kapitel 46 - Beans |
Die bisherigen Beans waren aus Canvas abgeleitet und repräsentierten damit elementare Komponenten. Ebenso leicht ist es möglich, zusammengesetzte Komponenten als Beans zu definieren und so größere Programmeinheiten wiederverwendbar zu machen.
Wird eine Bean beispielsweise aus der Klasse Panel abgeleitet, können darauf vordefinierte Dialogelemente platziert und mit Hilfe von setter-Methoden konfigurierbar gemacht werden. Im GUI-Designer erscheinen die unterschiedlichen Dialogelemente dann wie ein einziges. Meist spielt die Bean auch noch die Rolle eines Ereigniskonzentrators, d.h., sie registriert sich als Listener bei ihren eigenen Komponenten und verarbeitet diese so weit wie möglich selbst. Nach außen hin definiert sie ein abstrakteres Event-Modell, das an die Bedürfnisse der Gesamtkomponente angepasst ist. Statt den Client mit den Elementarereignissen der einzelnen Komponenten zu belasten, sendet sie nur noch Ereignisse, die das Verhalten der zusammengesetzten Komponente repräsentieren.
Die Konstruktion einer Panel-Bean ist prinzipiell nicht schwieriger als die einer einfachen Bean. Zusätzlicher Aufwand wird allerdings erforderlich, wenn die Eigenschaften der darin enthaltenen Komponenten zum Designzeitpunkt nicht mit einfachen getter- und setter-Methoden erledigt werden können. Die meisten Entwickler erwarten heute beispielsweise von einem Splitpanel (eine typische Panel-Bean), dass im GUI-Designer die einzelnen Komponenten per Drag-and-Drop darauf platziert werden können.
So weit wollen wir allerdings nicht in die Bean-Programmierung vordringen. Wir wollen nur die Grundprinzipien erklären und eine Klasse ButtonPanel entwickeln, die eine Gruppe von Radiobuttons kapselt. Die Anzahl der Radiobuttons, ihre Beschriftung und die Auswahl des selektierten Elements sollen frei definiert werden können. Ändert sich die Anzahl der Buttons oder wird ein anderer Button selektiert, soll die Bean ein PropertyChangeEvent versenden.
Das folgende Listing zeigt den Code für diese Klasse:
001 /* ButtonPanel.java */ 002 003 import java.awt.*; 004 import java.awt.event.*; 005 import java.beans.*; 006 import java.io.*; 007 008 public class ButtonPanel 009 extends Panel 010 implements Serializable, ItemListener 011 { 012 //---Instanzvariablen------------------------------------ 013 protected CheckboxGroup cbg; 014 protected Checkbox[] cb; 015 transient protected PropertyChangeSupport pcs; 016 017 //---Methoden-------------------------------------------- 018 public ButtonPanel() 019 { 020 cbg = new CheckboxGroup(); 021 cb = new Checkbox[0]; 022 initTransientState(); 023 } 024 025 //---Anzahl der RadioButtons----------------------------- 026 public void setButtonCnt(int cnt) 027 { 028 if (cnt != cb.length) { 029 int oldvalue = cb.length; 030 //Bisherige Buttons entfernen 031 if (cb.length > 0) { 032 removeAll(); 033 } 034 cb = new Checkbox[cnt]; 035 setLayout(new GridLayout(cnt, 1)); 036 for (int i = 0; i < cnt; ++i) { 037 cb[i] = new Checkbox( 038 "RadioButton " + i, 039 cbg, 040 (i == 0 ? true : false) 041 ); 042 cb[i].addItemListener(this); 043 add(cb[i]); 044 } 045 //PropertyChangeEvents senden 046 pcs.firePropertyChange("buttonCnt", oldvalue, cnt); 047 if (cnt > 0) { 048 setSelected(0); 049 } 050 //Neu layouten 051 setSize(getPreferredSize()); 052 invalidate(); 053 doLayout(); 054 Container owner = getParent(); 055 if (owner != null) { 056 owner.invalidate(); 057 owner.doLayout(); 058 } 059 } 060 } 061 062 public int getButtonCnt() 063 { 064 return cb.length; 065 } 066 067 //---Beschriftung der Buttons---------------------------- 068 public void setLabel(int index, String label) 069 { 070 if (index >= 0 && index < cb.length) { 071 cb[index].setLabel(label); 072 } 073 } 074 075 public String getLabel(int index) 076 { 077 String ret = "***invalid index***"; 078 if (index >= 0 && index < cb.length) { 079 ret = cb[index].getLabel(); 080 } 081 return ret; 082 } 083 084 //---Selektiertes Element-------------------------------- 085 public void setSelected(int index) 086 { 087 if (index >= 0 && index < cb.length) { 088 int oldvalue = getSelected(); 089 cb[index].setState(true); 090 pcs.firePropertyChange("selected", oldvalue, index); 091 } 092 } 093 094 public int getSelected() 095 { 096 int ret = -1; 097 for (int i = 0; i < cb.length; ++i) { 098 if (cb[i].getState()) { 099 ret = i; 100 break; 101 } 102 } 103 return ret; 104 } 105 106 //---Verwaltung der PropertyChangeListener--- 107 public void addPropertyChangeListener( 108 PropertyChangeListener l 109 ) 110 { 111 pcs.addPropertyChangeListener(l); 112 } 113 114 public void removePropertyChangeListener( 115 PropertyChangeListener l 116 ) 117 { 118 pcs.removePropertyChangeListener(l); 119 } 120 121 //---Reaktion auf Zustandsänderungen--------------------- 122 public void itemStateChanged(ItemEvent event) 123 { 124 Checkbox changedcb = (Checkbox) event.getItemSelectable(); 125 if (changedcb.getState()) { 126 for (int i = 0; i < cb.length; ++i) { 127 if (cb[i] == changedcb) { 128 pcs.firePropertyChange("selected", -1, i); 129 break; 130 } 131 } 132 } 133 } 134 135 //---Private Methoden------------------------------------ 136 /** 137 * Initialisierung der nichtpersistenten Instanzvariablen. 138 */ 139 private void initTransientState() 140 { 141 pcs = new PropertyChangeSupport(this); 142 } 143 144 /** 145 * Wird überlagert, um nach dem Deserialisieren den transienten 146 * Zustand zu initialisieren. 147 */ 148 private void readObject(ObjectInputStream stream) 149 throws IOException, ClassNotFoundException 150 { 151 stream.defaultReadObject(); 152 initTransientState(); 153 } 154 } |
ButtonPanel.java |
Die Bean verwaltet die Radionbuttons in dem Array cbg, das zunächst leer ist. Verändert sich ihre Anzahl durch Aufruf von setButtonCnt, werden alle bisherigen Buttons entfernt, neue in der gewünschten Anzahl angelegt und die registrierten Listener über die Änderung benachrichtigt. Zunächst haben die Buttons die Beschriftung »RadioButton 1«, »RadioButton 2« usw. Sie kann durch Aufruf von setLabel geändert werden. Der Zugriff auf das selektierte Element erfolgt mit getSelected und setSelected.
Um benachrichtigt zu werden, wenn der Benutzer per Mausklick die Selektion ändert, registriert sich die Bean in Zeile 042 als ItemListener bei den von ihr erzeugten Radiobuttons. Dadurch wird bei jeder Änderung die Methode itemStateChanged aufgerufen und die Bean kann ihrerseits ein PropertyChangeEvent an alle registrierten Listener versenden.
Abbildung 46.7 zeigt ein ButtonPanel mit vier Radiobuttons in der Beanbox:
Abbildung 46.7: Das ButtonPanel in der BeanBox
Das Listing treibt einigen Aufwand, um nach einer Größenänderung korrekt dargestellt zu werden (im Listing ab Zeile 050 zu sehen). Trotzdem war beispielsweise die Beanbox nicht dazu zu bewegen, bei einer Verminderung der Buttonzahl den nicht mehr benötigten Platz wieder freizugeben. Ist das dynamische Ändern der Größe ein wichtiges Feature, muss unter Umständen noch ein wenig experimentiert werden, um bei allen Clients zu den gewünschten Resultaten zu kommen. |
|
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 |