Creazione di uno stuolo di fagioli: crea componenti JavaBeans riutilizzabili

In questa breve serie, esaminiamo lo sviluppo di componenti software JavaBeans. In definitiva, la maggior parte dei bean verrà manipolata in un ambiente di sviluppo bean; tuttavia, qui ci occupiamo solo degli aspetti a livello di sorgente del framework. I vantaggi dello sviluppo di JavaBeans, ovvero lo sviluppo in base alla specifica JavaBeans, sono molteplici, tra cui:

  • I bean possono essere facilmente manipolati negli ambienti di sviluppo visivo da utenti che non necessitano di competenze tecniche nello sviluppo Java a livello di origine.

  • Grazie all'interfaccia standard, i bean sono facilmente distribuibili, il che consente ai componenti di terze parti di essere integrati più facilmente nelle attività di sviluppo.

  • Gli sviluppatori possono trasferire facilmente il codice che è stato sviluppato per un progetto in una libreria riutilizzabile di componenti, a cui è possibile accedere in futuri sforzi di sviluppo.

L'occhio del ciclone

Nel

prima parte di questa serie

, abbiamo sviluppato due semplici bean: un bean di allarme non visivo e un bean grafico con freccia sinistra / freccia destra. Entrambi sono stati aumentati con la visualizzazione

personalizzatore

e

informazioni sui fagioli

classi. Nei fagioli che copriremo questo mese, non forniremo personalizzatori; invece, ci concentreremo sull'utilizzo di bean e componenti esistenti per creare bean più grandi e migliori.

Prerequisiti

Come continuazione di una serie in due parti, assumerò familiarità con le questioni discusse nella puntata precedente, inclusi gli articoli e le risorse supplementari.

I fagioli

Dall'inizio alla fine di questa serie, sviluppiamo i seguenti fagioli:

AlarmBean Un bean non grafico che attiva un evento dopo un ritardo specificato.
ArrowBean

Un bean grafico con freccia sinistra / freccia destra.

ProgressBean

Un bean di visualizzazione grafica del progresso.

NumberFieldBean

Un TextFieldbean numerico grafico con pulsanti roll. Questo fagiolo utilizza il fagiolo ArrowBean.

FontChooserBean

Un bean grafico per la selezione dei caratteri. Questo bean utilizza il bean NumberFieldBean.

FontSelectorBean

Un bean di selezione dei caratteri grafico che visualizza il carattere corrente e fornisce pulsanti OK / Annulla. Questo bean utilizza il bean FontChooserBean.

FontDialogBean

Un bean di selezione dei caratteri grafico che fa apparire il selettore dei caratteri in una finestra di dialogo separata. Questo bean utilizza il bean FontSelectorBean.

Il mese scorso abbiamo discusso in dettaglio di AlarmBeane ArrowBeanfagioli; in questo episodio, discuteremo i fagioli rimanenti con diversi livelli di dettaglio.

Forse ti starai chiedendo perché stiamo costruendo tre bean di font. L'obiettivo finale è semplicemente quello di produrre un bean di selezione dei caratteri che fa apparire una finestra di dialogo dei caratteri quando l'utente fa clic su un pulsante. Questa attività si divide in modo molto naturale nei tre bean che produrremo: il primoèl'interfaccia utente per la selezione del font, il secondo aggiunge i controlli di dialogo e un campione di font, e il terzo introduce un pulsante per far apparire la finestra di dialogo e contiene le informazioni di base codice di gestione delle finestre di dialogo.

Senza i fagioli, dovremmo sviluppare questi articoli come componenti AWT specializzati o come una singola classe monolitica; utilizzando i fagioli, possiamo sviluppare le tre parti come fagioli indipendenti riutilizzabili a pieno titolo.

Il nostro scopo

Come per la prima puntata di questa serie, ci occupiamo solo dei berretti di queste classi e non dei veri e propri dadi e bulloni che li fanno funzionare. Di conseguenza, discuteremo dei fagioli in forma scheletrica, evidenziando in rosso i frammenti che sono di particolare rilevanza e lasciandoti gli altri dettagli da esaminare nel tuo tempo libero. Né ci occuperemo dei personalizzatori, che abbiamo trattato in modo sufficientemente dettagliato con la nostra discussione dei primi due fagioli.

Per vedere il lavoro forzato dietro i fagioli, controlla il codice sorgente completo.

Costruire il fagiolo ProgressBean

ProgressBean

è un semplice fagiolo di visualizzazione dell'avanzamento. Si tratta di un componente AWT personalizzato che visualizza un valore percentuale e una rappresentazione grafica a barre di questo valore, come mostrato nella figura seguente. Espone due proprietà: i valori della barra corrente e massimo.

Il valore attuale è esposto come proprietà osservabile . Le proprietà osservabili sono proprietà i cui cambiamenti possono essere osservati. Gli osservatori vengono registrati con il bean nello stesso modo in cui lo sono i listener di eventi e ricevono una notifica ogni volta che una proprietà cambia. Le proprietà individuali di un fagiolo devono essere rese esplicitamente osservabili dal fagiolo; non è possibile osservare le modifiche a una qualsiasi proprietà di qualsiasi bean.

Questo bean è implementato con le seguenti due classi:

  • ProgressBean - La principale classe di fagioli

  • ProgressBeanBeanInfo - La classe di informazioni sui fagioli

Classe ProgressBean

Il

ProgressBean class è la classe bean principale, un semplice componente AWT personalizzato e Java bean.

la classe pubblica ProgressBean estende il componente ... 

This bean is a lightweight component, so we extend Component instead of Canvas, and provide an appropriate paint() method. The lightweight component framework is more efficient than the traditional custom-component framework, requiring fewer resources of the local windowing system. As a component, we automatically inherit the serializability mandated by JavaBeans, and we provide the default no-arg constructor.

public void setBarground (Color c) ... public Color getBarground () ... public synchronized void setMaximum (int m) ... public int getMaximum () ... 

Here, we expose the Color property barground (the color of the displayed bar) and the int property maximum (the maximum bar value).

public synchronized void setValue (int v) { if (value != v) { value = v; repaint (); fireValueChange (); } } public int getValue () ... 

The int property value is observable, which means that we must inform all interested listeners whenever its value changes. To this end, we call our fireValueChange() method to inform the listeners whenever setValue() is called.

protected PropertyChangeSupport listeners = new PropertyChangeSupport (this); public void addPropertyChangeListener (PropertyChangeListener l) { listeners.addPropertyChangeListener (l); } public void removePropertyChangeListener (PropertyChangeListener l) { listeners.removePropertyChangeListener (l); } 

Here, we maintain a list of objects that are registered to be notified whenever an observable property changes. We use the class PropertyChangeSupport from the java.beans package to maintain this list. The constructor for this class requires us to specify the bean that will be the origin of property change events; in this case, it is this, and the methods that it provides allow us to maintain the list.

By exposing the methods addPropertyChangeListener() and removePropertyChangeListener(), we automatically indicate that this bean has observable properties. We do not, however, indicate which properties are observable. That information must be appropriately documented with the bean.

Protetto Integer oValue = new Integer (value); protected void fireValueChange () {listener.firePropertyChange ("value", oValue, oValue = new Integer (value)); }

Chiamiamo questo metodo per notificare agli ascoltatori un cambiamento nella nostra proprietà di valore ; usiamo il firePropertyChange()metodo del nostro elenco per propagare questa notifica. Il primo parametro è il nome della proprietà, che dovrebbe corrispondere al nome di una proprietà esposta; il secondo parametro è il vecchio valore della proprietà; e la terza proprietà è il nuovo valore. La PropertyChangeSupportclasse ritorna senza fare nulla se i valori vecchio e nuovo sono gli stessi.

Classe ProgressBeanBeanInfo

Il

ProgressBeanBeanInfoclass descrive semplicemente il ProgressBeanbean, oscurando qualsiasi informazione ereditata che desideriamo oscurare.

Creazione del bean NumberFieldBean

This bean implements a common user-interface component, the rollable number entry field -- a numeric text field that provides increment and decrement arrows, as shown in the figure below. This bean brings up an important JavaBeans concept:

programmatic manipulation of beans

.

Programmatic manipulation of beans refers to the mechanisms that JavaBeans provides for programmatically creating and accessing beans. Although it is possible to access beans using the standard Java object creation (new X ()) and type-casting mechanisms ((Y) x), it is recommended that you use the provided JavaBeans mechanisms to allow for future extension of the JavaBeans framework.

This bean is implemented with the following two classes:

  • NumberFieldBean -- The main bean class

  • NumberFieldBeanBeanInfo -- The bean information class

Class NumberFieldBean

The NumberFieldBean class, the main bean class, is an AWT container that adds three components: two ArrowBean beans and a TextField. Programmatic access to the ArrowBean class requires that we make use of the bean manipulation mechanisms I mentioned a moment ago.

The current numeric value is exposed as an observable property. Although it is a normal property that can be accessed and manipulated through the usual beans accessor methods, it is also observable, so listeners can register to be notified whenever its value changes. We do not fire an event when the user presses Return, although that would be an obvious extension to this class.

public class NumberFieldBean extends Container implements ActionListener ... 

We extend Container and implement ActionListener in order to receive events from the beans and AWT components that we use. Extending Container instead of the more traditional Panel means that this bean, like the ProgressBean bean is a lightweight component.

public NumberFieldBean () ... 

As a bean, we must provide a public no-arg constructor. Note that we should not provide other constructors for programmatic use; doing so would go against the JavaBeans access mechanism.

try { down = (ArrowBean) Beans.instantiate (getClass ().getClassLoader (), "org.merlin.beans.arrow.ArrowBean"); } catch (Exception ex) { ex.printStackTrace (); } 

Here, we create an ArrowBean using the programmatic beans instantiation mechanism. We don't use the standard Java new operator; instead, we use the instantiate() method of class Beans. We specify the ClassLoader to use for loading the bean class; in this case, we use our own ClassLoader and the fully qualified name of the bean class ("org.merlin.beans.arrow.ArrowBean"), and cast the resulting Object to the appropriate class.

Note that the instantiate() method may throw a variety of exceptions (for example, if the specified bean could not be located). We simply catch and display any such exceptions, which, by the way, should not occur if the bean is appropriately installed.

add ("East", (Component) Beans.getInstanceOf (down, Component.class)); 

Here, we cast the ArrowBean to a Component and add it as a normal Component. We don't use the standard (Component) type-casting mechanism, and we don't use the fact that our AlarmBean is a subclass of Component; instead, we use the getInstanceOf() method of class Beans. We specify the bean that we wish to cast and the Class object to which we wish to cast it (in this case, Component.class).

Although this approach makes little sense right now, future versions of JavaBeans will support beans composed of multiple class files, as well as beans that can expose different aspects of themselves as the different classes. For example, a bean could appear to subclass both Component and RemoteObject by providing two coupled classes: a Component and a RemoteObject. Using the JavaBeans type-casting mechanism, the appropriate bean object can be returned automatically, so beans can have apparent multiple-inheritance, although Java does not natively support this. For details, see the "Glasgow" JavaBeans specification. (A link to this spec is provided in the Resources section of this article.)

It is necessary for us to use these beans access mechanisms now, so we can transition our beans to future JavaBeans technologies without any problems.

down.setDirection (ArrowBean.LEFT); down.addActionListener (this); 

Here, we configure the ArrowBean using the setDirection() property accessor and the addActionListener() registration method. We can use these property accessors and listener registration methods directly on the bean we just created; it is only necessary to use the JavaBeans type-casting feature when we are accessing an aspect of a bean that is inherited from another class.

public synchronized void setValue (int v) { field.setText (String.valueOf (v)); fireValueChange (getValue ()); } public synchronized int getValue () ... 

Here, we expose the int property value, which is the value of this field. This property is observable, so we must notify listeners whenever it is changed. We do this by calling our fireValueChange() method.

public void setColumns (int c) ... public int getColumns () ... public synchronized void setMinimum (int m) ... public int getMinimum () ... public synchronized void setMaximum (int m) ... public int getMaximum () ... public synchronized void setStep (int s) ... public int getStep () ... 

Qui, esponiamo le colonne delleint proprietà , minimo , massimo e passo , che sono, rispettivamente, il numero di colonne visualizzate in , i valori minimo e massimo che questo campo dovrebbe contenere e l'importo di cui i pulsanti freccia dovrebbero valore. Queste proprietà non sono osservabili.TextField

Tieni presente che utilizziamo la sincronizzazione per garantire la sicurezza dei thread laddove appropriato.

public synchronized void actionPerformed (ActionEvent e) {int value = getValue (); if (e.getSource () == down) {if (value> minimum) {value = (value - step> value)? minimo: morsetto (valore - gradino); setValue (valore); }} ...