logo search
Методичка Java

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

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

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

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

Очевидно, что для некоторых типов событий обязательно создавать список слушателей. Хотя в случае 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() );