Смекни!
smekni.com

Общие представления о языке Java 5 (стр. 67 из 68)

/**

* Holds value of property titleShift.

*/

private int titleShift;

/**

* Getter for property titleShift.

* @return Value of property titleShift.

*/

public int getTitleShift() {

return this.titleShift;

}

/**

* Setter for property titleShift.

* @param titleShift New value of property titleShift.

*/

public void setTitleShift(int titleShift) {

int oldTitleShift = this.titleShift;

this.titleShift = titleShift;

propertySupport.firePropertyChange ("titleShift",

new Integer (oldTitleShift),

new Integer (titleShift));

repaint();//добавлено вручную

}

Правда, как и в предыдущем случае, в автоматически сгенерированный код сеттера пришлось добавить оператор repaint().

Свойства вида Constrained требуют проверки задаваемого значения свойства на принадлежность к области допустимых значений. Если значение не удовлетворяет этому условию, возбуждается исключительная ситуация. При изменении таких свойств порождается событие VetoableChangeEvent. Слово Vetoable происходит от “Veto able” - способный на накладывание ограничения, накладывание вето.

При задании свойств - массивов во всплывающем меню, вызываемом правой кнопкой мыши в узле Bean Patterns, следует пользоваться опцией Add/Indexed Property. Например, если мы выбрали параметры так, как указано на правом рисунке, приведённом выше, будет добавлен следующий код:

/**

* Holds value of property arr.

*/

private double[] arr;

/**

* Indexed getter for property arr.

* @param index Index of the property.

* @return Value of the property at <CODE>index</CODE>.

*/

public double getArr(int index) {

return this.arr[index];

}

/**

* Getter for property arr.

* @return Value of property arr.

*/

public double[] getArr() {

return this.arr;

}

/**

* Indexed setter for property arr.

* @param index Index of the property.

* @param arr New value of the property at <CODE>index</CODE>.

*/

public void setArr(int index, double arr) {

this.arr[index] = arr;

propertySupport.firePropertyChange ("arr", null, null );

}

/**

* Setter for property arr.

* @param arr New value of property arr.

*/

public void setArr(double[] arr) {

double[] oldArr = this.arr;

this.arr = arr;

propertySupport.firePropertyChange ("arr", oldArr, arr);

}

После добавления нового свойства следует заново скомпилировать проект (Build main project – F11). При этом, если при визуальном проектировании (Design) выделить компонент jTitledPanel1, его новые свойства появятся в окне jTitledPanel1[JTitledPanel]-Properties/ Properties сразу после компиляции проекта.

Добавление в компонент новых событий

Поскольку мы наследуем компонент от класса JPanel, большинство необходимых событий он уже умеет генерировать. Но в ряде случаев может потребоваться другой тип событий. В ряде случаев имеется возможность использовать готовые интерфейсы слушателей. Например, мы хотим, чтобы возникло событие java.awt.event.TextEvent, связанное с изменением текста заголовка. “Обычная” панель JPanel не имела свойств, связанных с текстом, и это событие в ней не поддерживалось. Интерфейс java.awt.event.TextListener имеет всего один метод textValueChanged(TextEvent e), так что в адаптере нет необходимости.

Для создания такого события для нашего компонента требуется использовать добавление поддержки события через Bean Patterns.

В Java имеется два типа источников событий:

· Unicast Event Source – источник порождают целевые объекты событий, которые передаются одному слушателю-приёмнику. “Cast” – список исполнителей, “Unit”- единичный, “Unicast” – от Unit и Cast - один обработчик, “Source” - источник. В этом случае список слушателей не создаётся, а резервируется место только для одного.

· Multicast Event Source - источник порождают целевые объекты событий, которые передаются нескольким слушателям-приёмникам. “Multi” – много, “Multicast” – много обработчиков. В этом случае для событий данного типа создаётся список слушателей.

Очевидно, что для некоторых типов событий обязательно создавать список слушателей. Хотя в случае Unicast Event Source реализация оказывается проще. В нашем случае в списке нет необходимости, поэтому выберем первый вариант. В выпадающем списке диалога имеется возможность выбрать некоторые интерфейсы слушателей из пакетов java.awt.event и javax.swing.event. Однако нам нужен интерфейс, поддерживающий событие java.awt.event.TextEvent, который в нём отсутствует. Поэтому мы укажем имя интерфейса java.awt.event.TextListener вручную.

Задание в компоненте нового типа событий

При выборе варианта Generate Empty (“Генерировать Пустое”) в коде компонента появятся пустые реализации методов добавления и удаления слушателей. Это достаточно экзотический случай, поэтому мы выберем вариант Generate Implementation (“Генерировать Реализацию”).

Если выбрать опцию Generate Event Firing Methods (“Генерировать методы “выстреливания событиями” ”), происходит автоматическая генерация заготовок fire-методов fireИмяСобытия, предназначенных для оповещения зарегистрированных слушателей. В случае Unicast-источников обход списка слушателй не требуется, поэтому нам нет необходимости отмечать данный пункт. А вот в случае Multicast-источника это наиболее часто требующееся решение. При этом обычно бывает желательно передавать в методы событие как параметр – и для этого надо выбрать опцию Pass Event as Parameter (“Передавать событие как параметр”).

Если пункт Generate Event Firing Methods отмечен, а опция Pass Event as Parameter не выбрана, событие не будет передаваться в fire-методы, а будет создано в самом fire-методе. Именно так происходит в примере для свойства sampleProperty, где вызов

propertySupport.firePropertyChange(PROP_SAMPLE_PROPERTY,

oldValue, sampleProperty)

приводит к порождению внутри метода firePropertyChange события PropertyChange.

Генерация кода, поддерживающего интерфейс java.awt.event.TextListener, приведёт для Unicast-источника без генерации fire-методов к появлению следующего кода:

/**

* Utility field holding the TextListener.

*/

private transient java.awt.event.TextListener textListener = null;

/**

* Registers TextListener to receive events.

* @param listener The listener to register.

*/

public synchronized void addTextListener(java.awt.event.TextListener

listener) throws java.util.TooManyListenersException {

if (textListener != null) {

throw new java.util.TooManyListenersException ();

}

textListener = listener;

}

/**

* Removes TextListener from the list of listeners.

* @param listener The listener to remove.

*/

public synchronized void removeTextListener(java.awt.event.TextListener listener) {

textListener = null;

}

Но в этом случае добавлять код, обеспечивающий порождение события, должен программист.

Если выбрана опция генерации fire-методов без передачи события как параметра, появится следующий дополнительный код по сравнению с предыдущим вариантом:

/**

* Notifies the registered listener about the event.

*

* @param object Parameter #1 of the <CODE>TextEvent<CODE> constructor.

* @param i Parameter #2 of the <CODE>TextEvent<CODE> constructor.

*/

private void fireTextListenerTextValueChanged(java.lang.Object object,int i){

if (textListener == null) return;

java.awt.event.TextEvent e = new java.awt.event.TextEvent (object, i);

textListener.textValueChanged (e);

}

Этот код также не обеспечивает автоматической генерации события в нашем компоненте, но даёт возможность сделать это путём добавления одной строчки в код метода setTitle – перед вызовом метода repaint()мы напишем

fireTextListenerTextValueChanged(this,

java.awt.event.TextEvent.TEXT_VALUE_CHANGED);

В качестве первого параметра fire-метода идёт ссылка на объект-источник события, в качестве второго – идентификатор типа события. Найти, где задаётся идентификатор, просто – достаточно перейти мышкой по гиперссылке java.awt.event.TextEvent, появляющейся в среде разработке при нажатии клавиши <CTRL>, и посмотреть исходный код конструктора. – Данную гиперссылку можно получить в строке

java.awt.event.TextEvent e = new java.awt.event.TextEvent (object, i);

в теле метода fireTextListenerTextValueChanged, в которой, собственно, и используется этот не очень понятный с первого взгляда параметр.

Теперь после компиляции проекта мы можем назначать обработчики событий типа TextValueChanged нашему компоненту. К сожалению, для того, чтобы событие textValueChanged появилось в списке событий компонента в окне jTitledPanel1[JTitledPanel]-Properties/Events, требуется закрыть среду NetBeans и зайти в неё вновь. Для свойств этот баг отсутствует – они появляются в окне jTitledPanel1[JTitledPanel]-Properties/ Properties сразу после компиляции проекта.

Теперь для нашего компонента можно назначать и удалять обработчик события textValueChanged как непосредственно на этапе визуального проектирования, так и программным путём.

Покажем, каким образом это делается на этапе визуального проектирования. Выделим компонент jTitledPanel1 и выберем в окне jTitledPanel1[JTitledPanel]-Properties/Events событие textValueChanged. Нажмём кнопку с тремя точками, находящуюся рядом с полем – вызовется диалог добавления и удаления обработчиков событий. Вообще, имеется правило – если название на кнопке или пункте меню кончается на три точки, это означает, что при нажатии на кнопку или выборе пункта меню появится какой-нибудь диалог.

Создание обработчика события на этапе визуального проектирования

Введём в качестве имени обработчика события (event handler) в качестве примера “myHandler” и нажмём “OK”. В списке обработчиков Handlers формы “Handlers for textValueChanged” появится имя myHandler. При закрытии этой формы по нажатию “OK” в исходном коде приложения (а не компонента!) появится код

private void myHandler(java.awt.event.TextEvent evt) {

// TODO add your handling code here:

}

Вместо комментария “// TODO add your handling code here:”, как обычно, следует написать свой код обработчика. Например, такой:

javax.swing.JOptionPane.showMessageDialog( null,"Text="+

jTitledPanel1.getTitle() );

Краткие итоги по главе 12

- Компонент – это:

  • автономный элемент программного обеспечения, предназначенный для многократного использования, который может распространяться для использования в других программах в виде скомпилированного кода класса;
  • подключение к этим программам осуществляется с помощью интерфейсов;
  • взаимодействие с программной средой осуществляется по событиям, причём в программе, использующей компонент, можно назначать обработчики событий, на которые умеет реагировать компонент.

- Компонент JavaBeans является классом Java и имеет три типа атрибутов:

  • Методы компонента JavaBeans не отличаются от других методов объектов в Java. Они описывают поведение компонента. Общедоступные методы компонента могут вызываться из других компонентов или из обработчиков событий.
  • Свойства (Properties) компонента JavaBeans характеризуют его внешний вид и поведение и могут быть изменены в процессе визуального проектирования. Это можно сделать с помощью редактора свойств (Property Editor), а некоторые из свойств – вручную (положение компонента, его размер, текст). Свойство задаётся комбинацией геттера и сеттера (метода по чтению и метода по записи).
  • События (Events) используются для связи между компонентами. При помещении компонента на экранную форму среда разработки исследует компоненты и определяет, какие программные события данный компонент может порождать (рассылать) и какие - получать (обрабатывать).

- Наиболее простым способом создания компонента является использование мастера среды NetBeans.