Christian Wilhelm Java Beans Grundlagen Überblick über den Vortrag: • Vorwort • Was bringen Java Beans? • Wie werden Java Beans erstellt? • Wie benutzt man Java Beans? Vorwort: In meiner Projektarbeit hatte ich es mir zum Ziel gesetzt ein Bean zur Datums- und Zeitauswahl mit automatischer Validierung zu realisieren: Aus den daraus gewonnen Erfahrungen verfasste ich in Word ein „How-To make a Bean“ Dokument, indem die grundlegenden Beaneigenschaften mit Codebeispielen enthalten sind. Dieser Vortrag basiert auf diesem How-To. Das Mini How-To steht im Word Format zum download bereit unter: www.ghent.de/beans.doc Was bringen Java Beans? Selbstgeschriebene Beans: • Wiederverwendbarkeit von Programmcode • Einheitliches Design von Oberflächen • möglicher Verkauf Fremderworbene Beans: • meist komplexer Funktionsumfang • meist fehlerfreier Code • teure und langwierige Eigenentwicklung entfallen Wie werden Java Beans erstellt? Da dieser Bereich der Schwerpunkt des Vortrages darstellt, möchte ich hier erneut eine kurze Gliederung der behandelten Themen aufführen: 1. Die BeanInfo Klasse 2. Der Property Editor 3. Der Customizer 4. Eventhandling bei Java Beans 5. Erzeugen eines JAR Archivs Die BeanInfo Klasse (1/2) Beans sind ganz normale Java Programme, die über “Setter” und “Getter” Funktionen ihre Parameter nach außen geben. Die eigentliche Beanfunktionalität kommt durch eine Klasse, die so heißt, wie die Beanklasse mit der Ergänzung: „BeanInfo”. In meinem Fall: Beanklasse: BeanInfoklasse: DateField.class DateFieldBeanInfo.class Diese BeanInfoklasse wird von java.beans.SimpleBeanInfo abgeleitet. Durch Überschreiben der public Image getIcon(int iconType) Methode, wird das Icon des Beans, das später in der Entwicklungsumgebung das Bean selbst symbolisiert, definiert. Die BeanInfo Klasse (2/2) Um die Parameter über Setter und Getter aus der Beanklasse in der Entwicklungsumgebung anpassen zu können, ist es nötig die public PropertyDescriptor[] getPropertyDescriptors() Methode zu überschreiben und die Setter und Getter zusammen mit der Eigenschaftbeschreibung in einem PropertyDescriptor Array zurückzugeben. Um zu zeigen, wie PropertyDescriptoren initialisiert werden, hier ein Beispiel: new PropertyDescriptor("dateformat",DateField.class,"getFormat","setFormat") Durch das Überschreiben der public PropertyDescriptor[] getPropertyDescriptors() Funktion besitzt das Bean nun nur noch die Eigenschaften, die mit Hilfe des PropertyDescriptor[] zurückgegeben wurden. Um wieder alle Eigenschaften in der Entwicklungsumgebung anzeigen zu können, bedarf es der public BeanInfo[] getAdditionalBeanInfo() mit der die BeanInfo einer oder mehrerer anderer Klassen (meist die Basisklasse der Beanklasse) zurückgegeben wird. Das Ergebnis sind alle normalen Eigenschaften des Beans plus die selbst erzeugten. Der Property Editor (1/2) Mit Hilfe der BeanInfo Klasse sind nur relativ einfache Eigenschaftsänderungen, wie die Übergabe von Parametern oder eine True/False Auswahl bei boolean Datentypen möglich. Um unterschiedliche Auswahlmöglichkeiten zur Verfügung zu stellen, wird ein eigener Property Editor benötigt. Diese Klasse wird java.beans.PropertyEditorSupport abgeleitet. In dieser Klasse werden die Methoden public String getAsText() public void setAsText(String Text) überschrieben. Um das Ganze dann anzeigen zu können, muss in der BeanInfo Klasse noch die Methode setPropertyEditorClass(class PropertyEditor) des PropertyDescription Objekts gesetzt werden. Ein mögliches Ergebnis könnte folgendermaßen aussehen: Der Property Editor (2/2) Falls man noch mehr Flexibilität benötigt, muss man dann anstelle der Methoden “setAsText” und “getAsText” die Methoden: isPaintable() mit true und dann die paintValue(Graphics g, Rectangle box) Methode mit den gewünschten Änderungen überschreiben. Hiermit sind dann auch grafische Effekte der Eigenschaft möglich, wie das Ändern der Hintergrund- oder der Vordergrundfarbe: Der Customizer (1/2) Mit einem Bean Customizer kann man mehrere (oder auch alle) spezifischen Eigenschaften eines Beans einstellen. Dies ist vor allem von Vorteil, wenn man komplexe Zusammenhänge innerhalb eines Beans hat. Zum Beispiel, das Eigenschaft A nur erscheint, wenn Eigenschaft B zuvor angewählt wurde. Um den Customizer aufzurufen, klickt man im JBuilder mit der rechten Maustaste im Designbaum, auf das Bean und wählt hier „Customizer“. Ich bediente mich des Customizers um meine Eigenschaften einfach und übersichtlich darzustellen. Zusätzlich versah ich den Customizer mit einem Hilfe Button, der die in meinem Bean verwendbaren Formatzeichen auflistet: Der Customizer (2/2) Um einen Customizer zu programmieren, verwendet man eine ganz normale Klasse, die man von einem JPanel ableitet und das Interface Customizer implementiert. Diese Klasse kann man nun wie gewohnt mit grafischen Elementen gestalten und designen. Sie sollte die Methode public void setObject (Object obj) überschreiben. In dieser Methode werden den Eigenschaften die Werte zugewiesen, die vielleicht schon teilweise mit den normalen Eigenschaften des JBuilders eingestellt wurden. Außerdem sollte man einen PropertyChangeListener implementieren. Durch diesen Listener werden nämlich die Properties aus der Propertyliste des JBuilders benachrichtigt und erhalten ebenfalls die, im Customizer, gesetzten Eigenschaften. Dadurch werden inkonsistente Einstellungen verhindert. Um aus diesem JPanel dann einen Customizer zu machen, wird in der BeanInfo des Beans die Methode getBeanDescriptor() überschrieben und die Klasse des Customizer zurückgegeben Eventhandling bei Java Beans (1/3) Das Eventhandling in einem Bean funktioniert genau gleich wie in normalen Java Programmen. Es muss nur sichergestellt werden, dass das Bean in seinen Eventhandlern das Event noch einmal feuert. Nur so ist es möglich, dass die Klasse, die das Bean implementiert hat, das Event bekommt und dann in dessen Eventhandler springt: Programm mit Bean Eventhandler Event Bean Eventhandler Eventhandling bei Java Beans (2/3) Um diese Funktionalität zu gewährleisten, muss zu erst einmal der StandardListener entfernt werden: public synchronized void removeFocusListener(FocusListener l) { super.removeFocusListener(l); if (focusListeners != null && focusListeners.contains(l)) { Vector v = (Vector) focusListeners.clone(); v.removeElement(l); focusListeners = v; } } Anschliessend wird ein eigener Listener erzeugt: private transient Vector focusListeners; Dieser eigene Listener wird nun an das Bean geaddet public synchronized void addFocusListener(FocusListener l) { super.addFocusListener(l); Vector v = focusListeners == null ? new Vector(2) : (Vector) focusListeners.clone(); if (!v.contains(l)) { v.addElement(l); focusListeners = v; } } Eventhandling bei Java Beans (3/3) Um nun ein Event zu feuern, benötigt man noch die Funktion: protected void fireFocusLost(FocusEvent e) { if (focusListeners != null) { Vector listeners = focusListeners; int count = listeners.size(); for (int i = 0; i < count; i++) { ((FocusListener) listeners.elementAt(i)).focusLost(e); } } } Diese Methode muss man nun im eigenen Eventhandler des Beans aufrufen um ein Event zu feuern: public void focusLost(FocusEvent e) { fireFocusLost(e); } Dabei übergibt man einfach das Event e. Nun reagiert das Bean wie jede andere Komponente auch auf die Events der Klasse, die es verwendet. Erzeugen eines JAR Archivs Um das Bean nun transportabel zu machen, verwendet man einen Zip Packer, packt alle erzeugten Klassen in ein Archiv, fügt noch ein Verzeichnis „Meta-inf“ das wiederum eine Datei „Manifest.mf“ enthalten muss dazu und benennt die Endung von .ZIP nach .JAR um. Die „Manifest.mf“ ist eine Textdatei, die in unserem Falle genau drei Zeilen enthält: Die erste Zeile gibt die Version des Manifests an. In meinem Fall: Manifest-Version: 1.0 Anschließend folgt der vollqualifizierte Pfad zur Beanklasse innerhalb des JARs an (hierzu muss die Verzeichnisstruktur innerhalb des JARs berücksichtigt werden). Die dritte Zeile lautet einfach: Java-Bean = True In meinem Fall sieht das Manifest folgendermaßen aus: Manifest-Version: 1.0 Name: DateField.DateField.class Java-Bean: True Wie benutzt man Java Beans? Praktische Vorführung in JBuilder 5