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

Поскольку мы наследуем компонент от класса 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.

ü Методы с названием fireИмяСобытия (“fire” – “стрелять”, в данном случае – “выстрелить событием”) осуществляют поочерёдный вызов зарегистрированных слушателей из списка для данного события, передавая им событие на обработку.

ü Методы addИмяСобытияListener и removeИмяСобытияListener обеспечивают для компонента возможность добавления и удаления объекта слушателя - обработчика события.

ü Если требуется задать в компоненте новые свойства или обеспечить генерацию компонентом новых типов событий событий, следует воспользоваться мастером, вызываемым через узел Bean Patterns. Таким же образом удаляются свойства и события компонента.

ü Для того, чтобы добавить компонент в палитру, следует открыть файл компонента в окне редактора исходного кода, и в меню Tools выбрать пункт Add to Palette. После чего в появившемся диалоге выбрать палитру, на которую будет добавлен компонент. Желательно выбирать Beans, чтобы не путать наши компоненты со стандартными.

ü Свойства вида Bound – обычные свойства. При изменении таких свойств порождается событие PropertyChange. Свойства вида Constrained требуют проверки задаваемого значения свойства на принадлежность к области допустимых значений. Если значение не удовлетворяет этому условию, возбуждается исключительная ситуация. При изменении таких свойств порождается событие VetoableChangeEvent.

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

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

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

 

ü Генерация события в компоненте обеспечивается вручную вызовом fire-метода или другим способом.

Задания

· Создать собственный компонент JTitledPane, описанный в данной главе.

· Усовершенствовать компонент, обеспечив добавление в него свойства titleColor. Подсказка: установка красного цвета рисования в качестве текущего цвета вывода графических примитивов для объекта Graphics g осуществляется вызовом метода g.setColor(Color.red).

· Усовершенствовать компонент, обеспечив генерацию в нём событий типа TitleShiftEvent, предварительно создав соответствующий интерфейс. По желанию можно добавить и событие изменения цвета заголовка.

· *По желанию учащегося: Усовершенствовать компонент, обеспечив добавление в него свойства titleFont и методов, обеспечивающих установку нужного размера и типа фонта.

 


 

Литература

  1. http://java.sun.com/ - сайт SUN Java Technology
  2. К.Арнольд,Дж.Гослинг. Язык программирования Java/Пер.с англ.-СПб:Питер,1997.-304 с.
  3. П.Нотон. Java. Справочное руководство/ Пер.с англ.-М.:Восточная книжная Компания,1996.-448 с.
  4. Н.И.Смирнов. Java 2: Учебное пособие.- М.:”Три Л”, 2000.-320 с.
  5. Б.Эккель.Философия Java.Библиотека программиста. / Пер.с англ.-СПб:Питер, 2001.-880 с.
  6. Сафонов В.О.Введение в Java-технологию : Учебное пособие.-Наука, 2002.- 187 с.

Дополнительная литература

(рекомендуется для изучения после чтения данного учебного пособия)

  1. М.Фаулер. Рефакторинг: улучшение существующего кода. / Пер.с англ.- СПб: Символ-Плюс, 2003. – 432 с.
  2. Джошуа Блох. JavaTM Эффективное программирование. / Пер.с англ.- М.: Издательство “Лори”, 2002.-224 с.