Опубликован: 04.12.2009 | Доступ: свободный | Студентов: 8417 / 657 | Оценка: 4.30 / 3.87 | Длительность: 27:27:00
Лекция 12:

Компонентное программирование

< Лекция 11 || Лекция 12: 1234

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

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

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

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

При выборе варианта 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-метода идет ссылка на объект-источник события, в качестве второго – идентификатор типа события. Найти, где задается идентификатор, просто

  • достаточно перейти мышкой по гиперссылке http://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. Нажмем кнопку с тремя точками, находящуюся рядом с полем – вызовется диалог добавления и удаления обработчиков событий. Вообще, имеется правило – если название на кнопке или пункте меню кончается на три точки, это означает, что при нажатии на кнопку или выборе пункта меню появится какой-нибудь диалог.

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

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

Введем в качестве имени обработчика события (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() );

Краткие итоги

  • Компонент – это:
    • автономный элемент программного обеспечения, предназначенный для многократного использования, который может распространяться для использования в других программах в виде скомпилированного кода класса;
    • подключение к этим программам осуществляется с помощью интерфейсов;
    • взаимодействие с программной средой осуществляется по событиям, причем в программе, использующей компонент, можно назначать обработчики событий, на которые умеет реагировать компонент.
  • Компонент 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 и методов, обеспечивающих установку нужного размера и типа фонта.
< Лекция 11 || Лекция 12: 1234
Полетаев Дмитрий
Полетаев Дмитрий
Не очень понятно про оболочечные Данные,ячейки памяти могут наверно размер менять,какое это значение те же операции только ячейки больше,по скорости тоже самое
Максим Старостин
Максим Старостин

Код с перемещением фигур не стирает старую фигуру, а просто рисует новую в новом месте. Точку, круг.