빈 무리 만들기 : 재사용 가능한 JavaBeans 구성 요소 만들기

이 짧은 시리즈에서는 JavaBeans 소프트웨어 구성 요소의 개발을 검토하고 있습니다. 궁극적으로 대부분의 Bean은 Bean 개발 환경에서 조작됩니다. 그러나 여기서는 프레임 워크의 소스 수준 측면에만 관심이 있습니다. JavaBeans 개발 (즉, JavaBeans 사양으로 개발)의 장점은 다음과 같습니다.

  • Bean은 소스 수준의 Java 개발에 기술적으로 능숙 할 필요가없는 사용자가 시각적 개발 환경에서 쉽게 조작 할 수 있습니다.

  • 표준 인터페이스로 인해 Bean은 쉽게 배포 할 수 있으므로 타사 구성 요소를 개발 작업에 더 쉽게 통합 할 수 있습니다.

  • 개발자는 한 프로젝트 용으로 개발 된 코드를 재사용 가능한 구성 요소 라이브러리로 쉽게 전송할 수 있으며 향후 개발 노력에서 액세스 할 수 있습니다.

폭풍의 눈

에서

이 시리즈의 첫 번째 부분

, 우리는 비 시각적 알람 빈과 그래픽 왼쪽 화살표 / 오른쪽 화살표 빈의 두 가지 간단한 빈을 개발했습니다. 둘 다 시각적으로 증가했습니다.

커 스터 마이저

콩 정보

클래스. 이번 달에 다루는 빈에서는 커 스터 마이저를 제공하지 않을 것입니다. 대신, 우리는 더 크고 더 나은 빈을 만들기 위해 기존 빈과 구성 요소를 사용하는 데 집중할 것입니다.

전제 조건

두 부분으로 구성된 시리즈의 계속으로, 나는 보충 기사 및 리소스를 포함하여 이전 기사에서 논의 된 문제에 익숙하다고 가정합니다.

이 시리즈의 시작부터 끝까지 우리는 다음 빈을 개발합니다.

AlarmBean 지정된 지연 후 이벤트를 발생시키는 그래픽이 아닌 Bean입니다.
ArrowBean

그래픽 왼쪽 화살표 / 오른쪽 화살표 Bean.

ProgressBean

그래픽 진행 표시 빈.

NumberFieldBean

TextField롤 버튼이 있는 그래픽 숫자 빈. 이 빈은 ArrowBean 빈을 사용합니다.

FontChooserBean

그래픽 글꼴 선택기 빈. 이 빈은 NumberFieldBean 빈을 사용합니다.

FontSelectorBean

현재 글꼴을 표시하고 확인 / 취소 단추를 제공하는 그래픽 글꼴 선택기 Bean입니다. 이 빈은 FontChooserBean 빈을 사용합니다.

FontDialogBean

별도의 대화 상자에서 글꼴 선택기를 팝업하는 그래픽 글꼴 선택기 Bean입니다. 이 빈은 FontSelectorBean 빈을 사용합니다.

우리는 지난 달에 AlarmBeanArrowBean콩에 대해 자세히 논의했습니다 . 이 에피소드에서는 다양한 수준의 세부 사항으로 나머지 콩에 대해 설명합니다.

왜 우리가 세 개의 폰트 빈을 만들고 있는지 궁금 할 것입니다. 궁극적 인 목표는 사용자가 버튼을 클릭 할 때 글꼴 대화 상자를 팝업하는 글꼴 선택기 빈을 생성하는 것입니다. 이 작업은 매우 자연스럽게 우리가 생성 할 세 가지 빈으로 나뉩니다. 첫 번째는 글꼴 선택을위한 사용자 인터페이스이고, 두 번째는 대화 상자 컨트롤과 글꼴 샘플을 추가하고, 세 번째는 대화 상자를 팝업하는 버튼을 소개하고 기본을 포함합니다. 대화 처리 코드.

빈이 없으면 이러한 항목을 특수 AWT 구성 요소 또는 단일 모 놀리 식 클래스로 개발해야합니다. 빈을 사용하면 세 부분을 자체적으로 재사용 할 수있는 독립적 인 빈으로 개발할 수 있습니다.

우리의 범위

이 시리즈의 첫 번째 기사와 마찬가지로, 우리는 이러한 클래스의 비 니즘에만 관심이 있으며이를 틱하게 만드는 실제 너트와 볼트에는 관심이 없습니다. 결과적으로 우리는 골격 형태의 콩에 대해 논의하고 특정 관련성있는 조각을 빨간색으로 강조 표시하고 여가 시간에 자세히 살펴볼 수 있도록 다른 세부 정보를 남겨 둡니다. 우리는 처음 두 개의 빈에 대한 논의에서 충분히 자세히 다룬 커 스터 마이저에도 관심이 없습니다.

콩 뒤에있는 강제 노동을 보려면 전체 소스 코드를 확인하십시오.

ProgressBean 빈 빌드

ProgressBean

간단한 진행률 표시 빈입니다. 아래 그림과 같이 백분율 값과이 값의 그래픽 막대 표시를 표시하는 사용자 지정 AWT 구성 요소입니다. 현재 및 최대 막대 값의 두 가지 속성을 표시합니다.

현재 값은 관찰 가능한 속성으로 노출됩니다 . 관찰 가능한 속성은 변경 사항을 관찰 할 수있는 속성입니다. 옵저버는 이벤트 리스너와 같은 방식으로 빈에 등록되며 속성이 변경 될 때마다 알림을받습니다. 빈의 개별 속성은 빈이 명시 적으로 관찰 할 수 있어야합니다. 빈의 속성에 대한 변경 사항을 관찰하는 것은 불가능합니다.

이 Bean은 다음 두 클래스로 구현됩니다.

  • ProgressBean -메인 빈 클래스

  • ProgressBeanBeanInfo -빈 정보 클래스

ProgressBean 클래스

그만큼

ProgressBean class는 메인 빈 클래스, 간단한 사용자 지정 AWT 구성 요소 및 Java 빈입니다.

Public 클래스 ProgressBean이 Component를 확장합니다. 

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.

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

리스너에게 value 속성 의 변경 사항을 알리기 위해이 메서드를 호출 합니다. firePropertyChange()이 알림을 전파하기 위해 목록 의 방법을 사용합니다 . 첫 번째 매개 변수는 속성의 이름이며 노출 된 속성의 이름과 일치해야합니다. 두 번째 매개 변수는 속성의 이전 값입니다. 세 번째 속성은 새 값입니다. PropertyChangeSupport아무것도하지 않고 클래스 반환 이전 및 새 값은 동일합니다.

ProgressBeanBeanInfo 클래스

그만큼

ProgressBeanBeanInfo클래스는 단순히 ProgressBean빈을 설명하고 우리가 모호하게하려는 상속 된 정보를 모호하게합니다.

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 () ... 

여기에서 column , minimum , maximumstepint 속성 을 노출합니다.이 속성 은 각각에 표시되는 열 수 ,이 필드가 보유해야하는 최소값 및 최대 값, 화살표 버튼이 값. 이러한 속성은 관찰 할 수 없습니다.TextField

적절한 경우 스레드 안전성을 보장하기 위해 동기화를 사용합니다.

공개 동기화 무효 actionPerformed (ActionEvent e) {int value = getValue (); if (e.getSource () == down) {if (값> 최소값) {값 = (값-단계> 값)? 최소 : 클램프 (값-단계); setValue (값); }} ...