В |
этой главе вы узнаете дополнительные сведения о создании Ьеап-компонентов Основным механизмом обучения будет исследование bean-компонента, который предназначен для вывода показаний времени.
В данной главе рассматриваются следующие вопросы:
■ Выбор предка Ьеап-компонента.
■ Добавление свойств в Ьеап-компонент.
■ Дополнительная информация, касающаяся работы с Beanlnfo-файлами.
■ Фильтрация отображения свойств Ьеап-компонента для пользователя.
■ Управление видимостью свойств, унаследованных от компонента-предка.
■ Перекрытие существующих свойств.
■ Работа с таймерами.
■ Перекрытие метода рисования элемента управления.
Также мы проведем краткое обсуждение вопроса, как разработать такую архитектуру для bean-компонентов, чтобы они были простыми в управлении.
Программа-пример, используемая в этой главе, можно найти в каталоге Clock Среди сопровождающих книгу материалов. В этой главе мы будем использовать BeansExpress, функцию JBuilder, входящую в состав редакций SE и Enterprise. Для тех, кто использует редакцию Personal, в данной главе приводится код, который BeansExpress генерирует автоматически.
Вы уже сталкивались с bean-компонентом в главе 18, хотя его появление там можно назвать преждевременным. Если вы прочтете эту главу, то обнаружите небольшой bean-компонент, производный от класса BasePanelButton. При повторном изучении этого класса вы сможете многое узнать по поводу JavaBean-компонентов, а Также о создании Bean-компонентов, реагирующих на события.
Bean-компонент Clock
Что же, самое время заняться созданием Ьеап-компонента Clock. Начните новый проект и добавьте в него приложение, назвав его Clock. Если вам нужна помощь при создании приложения по умолчанию, еще раз прочтите главу 3. Чтобы создать но — Bbiii компонент EIfCIock, являющийся потомком класса JComponent, Воспользуйтесь
пунктом меню File ∣ New ∣ JavaBean. Вы также могли в качестве класса-предка выбрать JPanel, Но JComponent Все таки предпочтительнее ввиду своей легковесности.
Перейдите в режим конструирования для объекта EIfCIock и поместите на него элемент управления JTextFieId. Убедитесь, что у компонента Clock свойство Layout установлено равным BorderLayout. Для JTextFieId установите для свойства Constraints значение Center. После этого компонент JTextFieId должен занять всю площадь вашего элемента управления.
Добавление свойств в Ьеап-компонент
Переместите фокус на объект EIfCIock, после чего перейдите на закладки просмотра файлов, находящиеся под редактором, и откройте BeansExpress Выберите закладку Properties. Добавьте в проект два новых свойства — timer и running:
■ Чтобы создать свойство timer, щелкните на кнопке Add Property. В поле name введите значение timer, в поле type — javax. swing. Timer. Не следует отмечать флажки Getter и Setter для методов извлечения и присвоения значений, и не следует показывать это свойство через Beanlnfo-файл. За справкой обращаетесь к рисунку 35.1.
■ Чтобы создать свойство Running, Щелкните на кнопке Add Property. В поле name введите значение running, в поле type — boolean. Отметьте флажки Getter и Setter для методов извлечения и присвоения значений, а также сделайте это свойство видимым через Beanlnfo-файл, как показано на рис. 35.2.
……….. имин Кнопка эллипсиса, расположенная рядом с полем Туре, позволяет осуществлять поиск сложных типов. Простые типы, например int или boolean, потребуется Вводить вручную.
![]() |
![]() |
Перейдите в окно исходного кода. Обратите внимание на то, что свойство Running После создания использует метод присвоения значений SetRunning И метод извлечения значений IsRunning. Это соответствует в Java стандартному соглашению для булевых переменных:
Public Void SetRunning(Boolean Running)
{
This, running ■= running;
)
Public boolean isRunning()
{
Return Running;
)
Перейдите в раздел метода Jbinit И введите следующее: Timer = Timer
Переместите курсор на второй экземпляр слова "timer" или непосредственно после него. Нажмите комбинацию клавиш Ctrl+J. В программу должен автоматически вставиться следующий код:
Timer = new javax. swing. Timer(, new ActionListenerO
{
Public void actionPerformed(ActionEvent e)
{
)
)) ;
При нажатии Ctrl+J осуществляется вызов механизма JBuilder Code Template (Шаблон кода JBuilder). Он поместит курсор после открытой скобки в вызове конструктора Timer: Timer(. Сейчас необходимо ввести, с каким интервалом вы хотите осуществлять вызов своего кода: Timer (250, New ActionListenerO . . .
Теперь наберите следующий код в теле метода ActionPerformed:
Timer = new javax. swing. Timer(250, new ActionListenerO {
Public void actionPerformed(ActionEvent e)
{
Date d = new Date() ;
ɔTextFieldl. SetText(d. toString());
}
));
Отредактируйте метод SetRunning, Чтобы он приобрел следующий вид:
Public void setRunning(boolean running)
{
This running = running; if (this. running)
Timer. start(); else
Tiner. stop () ;
)
Откомпилируйте полученный код. Если у вас возникли проблемы, перейдите в верхнюю часть своего файла и убедитесь, что там присутствуют следующие операторы import:
Import java. awt. event.*; import java. util.*;
Используя инструмент Classlnsight, JBuiIder версии 7 и выше организует поддержку автоматической вставки выражений import в файлы исходного кода. Если вы введете оператор, который JBuiIder не сможет понять, он подчеркнет этот оператор красным цветом. Щелкните на типе, выделенном красным цветом, и возникнет небольшое однострочное диалоговое окно Classlnsight. Щелкните на пиктограмме увеличения, и появится диалоговое окно Classlnsight. Часто оно будет содержать именно тот элемент, который вам нужно добавить в свой оператор import. В таких случаях, для того чтобы его добавить, необходимо щелкнуть на кнопке OK. Иногда окно может содержать множество элементов. Может возникнуть такая ситуация, что вам даже придется искать требуемый оператор import. В любом случае, окно Classlnsight поможет быстро добавить Выражения Import в свой проект. Эта тема более подробно обсуждается в главе 7.
Переключитесь на компонент Framei И перейдите в режим конструирования. Выберите Bean Chooser при помощи маленькой пиктограммы, расположенной ниже пиктограммы со стрелкой в палитре компонентов (см. рис. 35.3).
ABtCtock ⅛ Framel J
![]() |
![]() |
Swing ) s ʤ Contain** I DataExpraea 1 CbSwirv I More ctoSw⅛v ∣ CtoSwInr Mrddb 1 HernetBeana, XML! E JB) AWT ∣ CORBA J Xlasd ∣ PVferkd ∣ Other |
Рис. 35.3. Выбор Bean Chooser Из Палитры Компонентов
C помощью открытого Bean Chooser вы можете выполнять поиск класса, который нужно вставить в проект, как показано на рис. 35.4. Когда вы выбираете класс, курсор приобретает вид крестика. C помощью курсора поместите компонент на Framel, Как вы бы помещали любой другой компонент.
![]() |
![]() |
G JJurfdeF C√ικrf^∕r4ιβt∣⅛∕Srf JivnzjhbooWJawaRpmww br∙W*rc∕Hock∕Fr4ιπw1.jθVΛ
Swthg IswtngCortaawra)∣ MaEnmaI dbSwtng∣ Mm IfcSwtig I dKMngModafct WamatBaana 1M1К *111
<E5*jtf-ββB — «— J[<^∙*=ar I
"i"∏h
Sun Dac 2318:47:48 PST 2001 •
Source Dea¾n) Baa»’*⅝∣∣-1 Рос| ⅛atory∣
На этом этапе у вас имеется грубый макет часов. Чтобы его использовать, выберите созданный вами новый компонент и перейдите в инспектор. Для свойства running установите значение True. Когда все готово, ваши часы должны начать тикать в панели конструктора пользовательского интерфейса JBuilder, как показано на рис. 35.5.
Вы могли обратить внимание на то, что на экранном снимке, представленном на рис. 35.5, панель проекта, панель структуры и панель сообщений скрыты. Я говорил об этом ранее, но думаю, что будет полезно напомнить, что включать и выключать эти панели можно комбинациями клавиш Ctrl+Alt+P, Ctrl+Alt+S и Ctrl+Alt+M. Чтобы Закрыть их все одновременно, нажмите Ctrl+Alt+Z.
Совершенствование компонента Clock
C помощью JBuilder создание инструмента вроде компонента Clock — потрясающе простая задача. Однако создание ядра компонента — это лишь малая часть работы по созданию компонента. В таком виде этот компонент никого бы не заинтересовал. Он слишком некрасив, и у него не очень-то много функций.
Одна из основных проблем, которые вы могли заметить в компоненте, заключается в том, что его свойство font не работает корректно. В частности, изменения свойства font, которые вы делаете с помощью инспектора, не оказывают никакого влияния на элемент управления.
Причину проблемы можно выявить практически сразу. Видимое в данный момент свойство font содержит значение шрифта для элемента JComponent или JPanel, на котором основан компонент. Однако текст, который написан на компоненте, выводится через элемент управления JTextField, который расположен на панели.
Проблему можно решить двумя путями:
■ Вынести свойство font объекта JTextField вместо свойства font объекта JPanel.
■ Удалить JTextField И самостоятельно Замена свойства Existing Давайте рассмотрим эти варианты по |
ζ∣3 Htηw Property |
■ Pi inert» Г ιm : Jfonl Type JiwnawtFont P Э >∙^^’ ‘⅛*⅜iS∙ |
RJi |
Clock. Убедитесь, что фокус находится на I B-IP1Hfo Pata — Перейдите на закладку Properties и создайте Заполните его так, как показано на рис. 35.6. Убедитесь, что вы добавили методы из- |
I B⅛⅝4f∏n∏m I` Jtorrt : Shortdnscripllon: ∣ Jforil |
⅜PP⅛ 1 |
Рис. 35.6. Создание свойства Font |
Ните на кнопке OK, то увидите сообщение, |
P’ Heansrxpress Message |
Рис. 35.7. Перекрытие существующего свойства |
Го свойства Font Класса JPanei На новое свойство Font Разрабатываемого нами класса. По умолчанию код, который вставляет в ваше приложение BeansExpress, выгля Дит следующим образом: Public void setFont(java. awt. Font font) { This, font = font; } Public java. awt. Font getFont () { Return font; ) |
Вам потребуется изменить его, чтобы он выглядел так: |
Public java. a⅞rt. Font getFont() { If (jTextFieldl ’= null) return jTextFieldl. getFont(); Else Return null; } Public void setFont(java. awt. Font font) { If (jTextFieldl ’= null) JTextFieldl. setFont(font); |
![]() |
![]() |
Теперь изменения, вносимые в свойство Font Класса ElfClock В инспекторе, будут работать в соответствии с вашими ожиданиями. Пример компонента часов с новым свойством Font Представлен на рис. 35.8.
На рис. 35.8 вы можете видеть, что текст в окне размещен по центру. Я достиг этого, добавив в метод jbinit для компонента часов следующий код:
JTextFieldl. SetHorizontalAlignment(SwingConstants. CENTER); JTextFieldl. SetRequestFocusEnabled(false);
Вторая строка представленного здесь кода включает для элемента управления режим "только для чтения". Пользователь не сможет переключить фокус на этот элемент управления, и потому не сможет изменить выводимый им текст.
На этом этапе код нашего компонента для одной из версий компонента часов завершен. Вы можете увидеть полный исходный код в листинге 35.1.
Листинг 35.1. Исходный код первой версии компонента Clock
Package |
Clock; |
Import |
Java. awt.*; |
Import |
Java. awt. event.*; |
Import |
Java. util.*; |
Import |
J avax. swing.*; |
Import |
J avax. swing. Timer; |
∕** |
|
* <р>Простой компонент Vacoβ<∕p> |
* Sauthor Charlie Calvert
* Sversion 1.0 */
Public class ElfClock extends JPanel
{
BorderLayout borderLayoutl = new BorderLayoutO; ∕** Таймер, управляющий часами*/
Timex timer = null;
/** Работают ли часы */
Private boolean running;
/** Элемент управления для вывода времени и даты */
JTextField JTextFieldl = new JTextFieldO ;
/**
* Конструктор */
Public ElfClockO
{
Try
(
Jblnit() ;
}
Catch(Exception ex)
{
Ex. printStackTrace();
)
}
∕**
* Метод инициализации визуальных компонентов в JBuilder
*
* 0throws Exception */
Private void JbInit() throws Exception
{
JTextFieldl. setText("JTextFieldl");
JTextFieldl. SetHorizontalAlignnient (SwingConstants. CENTER) ; JTextFieldl. SetRequestFocusEnabled(false); this. SetLayout(borderLayoutl);
Timer = new Javax. swing. Timer(250, new ActionListenerO {
Public void BCtionPerformed(ActionEvent e)
{
Date d = new Date();
JTextFieldl. setText(d. toString());
}
1) ;
This. add(JTextFieldl, BorderLayout. CENTER);
)
∕**
* Свойство включающее и выключающее часы
*
* @param running Остановить или запустить часы */
Public void SetRunning(boolean running)
{
This. running = running; if (this. running)
Timer. start();
Else
Timer. stop () ;
)
∕**
* Определяет, активны ли часы
*
* 6return Работают ли часы */
Public boolean getRunning()
{
Return running;
}
∕**
* Часть Get Возвращает свойство Font Для JTextField
*
* БReturn Шрифт, запрошенный пользователем */
Public java. awt. Font getFont()
{
If (jTextFieldl! = null)
Return jTextFieldl. getFont() ;
Else
Return null;
}
∕**
* Часть Set Свойства Font.
*
* Gparam font Шрифт, показываемый пользователю */
Public void setFont(java. awt. Font font)
{
If (jTextFieldl!= null)
JTextFieldl. setFont(font);
}
Прямое рисование текста на элементе управления
Теперь мы собираемся заново написать код элемента управления EifClock Таким образом, чтобы достигнуть большей степени контроля над его внешним видом. Первым шагом этого процесса является удаление JTextField.
Если вы понимаете принцип работы JBuilder, то должны знать, что самый простой способ удалить JTextField Заключается в том, чтобы навести фокус на EifClock. java, Перейти в режим конструирования, выполнить один щелчок на JTextField В конструкторе пользовательского интерфейса, после чего нажать клавишу Delete. При этом будет удален сам компонент и большая часть ссылок в коде на этот компонент. В частности, JBuilder найдет ссылки на JTextField В методе Jblnit, Однако он пропустит одну ссылку в анонимном ActionListener Для класса Timer, А также ссылки в методах извлечения и присвоения значений свойства Font. Тем не менее, вы можете очистить методы извлечения и присвоения значений свойства Font, Открыв BeansExpress, после чего перейти на закладку Properties, выбрать свойство font и щелкнуть на кнопке Remove Property (Удалить свойство). Это можно сделать, так как свойство Font Было связано с компонентом JTextFieid, Который мы уже удалили.
Может быть, я выгляжу немного несерьезным, предполагая, что вы станете удалять методы извлечения и присвоения значений свойства font через BeansExpress. На практике, вы, скорее всего, просто удалите код в редакторе. Однако если бы вам нужно было удалить десять свойств, а еще несколько — сохранить, проще Всего было бы решить эту проблему с помощью BeansExpress.
Единственной оставшейся ссылкой на JTextFieid является ссылка в анонимном слушателе. Вы можете удалить эту ссылку, сохранив при этом код, создающий объект Date:
Timer = new javax. swing. Timer(250, new ActionListenerO {
Public void actionPerformed(ActionEvent e)
{
Date d = new Date () ;
∕∕jTextFieldl. setText(d. toString());
}
});
Перекрытие метода Paint
Теперь пришло время перекрыть метод paint компонента и приступить к процессу рисования часов самостоятельно:
Public void paint(Graphics g)
{
Super. paint(g) ;
Date d = new Date () ;
G. drawString(d. toString(), 10, 30);
![]() |
![]() |
![]() |
![]() |
Timer = new javax. swing. Timer (250, new ActionListenerO {
Public void actionPerformed(ActionEvent e)
{
Repaint();
}
H;
Получается, что этот метод рисования часов оказался не настолько сложным в реализации, как это могло показаться на первый взгляд. Но, конечно же, вряд ли кто — то может найти самый лучший способ вот так, с первого раза Вместо этого про-
Цесс написания кода получается итеративным. Вы пишете первую версию, которая хоть как-нибудь да работает. В худшем случае она должна хотя бы компилироваться и запускаться. Процесс написания кода помогает вам думать о том, Что вы делаете, и помогает больше узнать об используемых технологиях. Так что, возможно, во второй раз у вас получится код, который будет немного лучше, а в третий раз он, возможно, будет еще чуть-чуть лучше. И так далее. Цель состоит в том, чтобы хранить свой код в таком состоянии, чтобы его всегда можно было компилировать и тестировать.
Совершенствование элемента управления
На данном этапе мы можем задать себе множество вопросов. Первым может возникнуть вопрос, хотим ли мы, чтобы наш элемент управления был порожден от класса JPanel, или чтобы он попрождался от JCornponent?
Поскольку мы хотим получить больший контроль над компонентом, одна из вещей, которую я люблю делать в таких случаях, заключается в том, чтобы выделить сложные или отдельные части кода существующего объекта и поместить их в свой собственный мир. В частности, рисование поверхности часов в действительности представляет собой отдельную задачу, которую можно легко изолировать. В результате, я вставляю ее в отдельный объект с именем DrawClock, представленный в листинге 35.2.
Листинг 35.2. Простейший способ рисования часов
Package clock;
Import java. awt.*;
Import java. util.*;
Public class DrawClock
{
Public DrawClock()
{
}
Public void draw(Graphics g)
{
Date d = new Date();
G. drawstring(d. toString(), 10, 30);
}
}
Для того чтобы создать этот файл, выберите в меню пункт File ∣ New Class. Дайте классу имя DrawCIock. Предком, или базовым классом, должен быть класс Java. lang. object. Поместите его в тот же пакет Clock, Что и компонент Eifdock. В мастере нового класса New Class Wizard выберите все опции, кроме Generate main method.
В первой версии нового класса вся работа локализована в единственном методе с именем Draw. В листинге 35.2 вы можете видеть, что метод Draw Всего лишь создает экземпляр класса Date, После чего выводит на экран текущее время через экземпляр класса Graphics2D. Не забудьте добавить два оператора Import, Показанные в верхней части листинге 35.2.
Вы могли сделать метод draw статическим или создать экземпляр класса DrawClock в разделе инициализации компонента EifClock:
Public class ElfClock extends JComponent {
DrawClock drawClock = new DrawClock();
BorderLayout borderLayoutl = new BorderLayout() ; private javax. swing. Timer timer;
Etc…
)
Вызов нового класса из компонента EifCiock осуществляется следующим образом:
Public void paint (Graphics g)
{
Super. paint(g); drawClock. draw(g);
}
B данном коде сначала выполняется вызов метода paint предка. Затем он передает ответственность за рисование второму классу.
Такая архитектура полезна, потому что она позволяет нам подключать различные часы в главный объект путем создания экземпляра класса DrawClock Другого вида. Например, класс DrawPieceClock, Созданием которого мы займемся в следующей главе, может выглядеть как изображение, показанное на рис. 35.10.
Видимость свойств нового объекта часов
Нам не нужно, чтобы для компонента EifClock в инспекторе JBuilder были видимы свойства класса-предка. Это очень простой компонент, и нет необходимости заваливать пользователя кучей информации, которую он никогда не будет использовать.
Ладно, ладно. Может быть, некоторым разработчикам упомянутая информация и понадобится. Но давайте предположим, что такого не случится. Бывают случаи, когда вам действительно нужно сокрыть свойства или события, и для вас этот пример Будет хорошей возможностью увидеть, как работает система.
Чтобы сокрыть свойства класса-предка, создайте класс Beaninfo. Это можно сделать с помощью закладок вида файла, переключившись на закладку Bean. В BeansExpress перейдите на закладку Beanlnfo.
Убедитесь в том, что на закладке Beanlnfo не отмечена опция Expose superclass Beanlnfo (Показать Beanlnfo базового класса). Щелкните на кнопке Generate Beanlnfo. Для уверенности в том, что был создан правильный код, просмотрите сгенерированный Beanlnfb-файл и убедитесь в том, что там нет метода с именем GetAdditionaiBβaninfo. Если такой метод есть, удалите или закомментируйте его.
На рис. 35.11 вы можете видеть, на что похож инш. ч’ктор, если свойства класса — предка являются видимыми. А вот на рис. 35.12 показан внешний вид инспектора,
![]() |
![]() |
Когда свойства класса-предка невидимы. Если вам нужно больше информации, просмотрите разделы глав 33 и 34, в которых обсуждается BeanInfo.
После успешного сокрытия тех свойств компонента-предка, которые не следует показывать, вы можете обнаружить, что все же некоторые из них стоило бы сделать видимыми. Это довольно-таки распространенная ситуация. Как правило, нужно сокрыть большую часть информации классов-предков, но все же некоторые методы стоит сделать видимыми
В частности, существуют два свойства класса-предка, которые потребуется сделать видимыми в часах. Одно из них — это цвет текста (свойство Foreground), В который будут окрашены цифры, отображаемые на часах. Другим свойством является цвет фона. Воспользуйтесь BeansExpress для добавления этих двух свойств.
Первое свойство — это цвет текста. В панели содержимого переместите фокус на EIfCIockjava. Переключитесь на BeansExpress и откройте закладку Properties. Создайте новое свойство с именем foreground и типом java. awt. Color. Создайте для свойства методы извлечения и присвоения значений и сделайте свойство видимым через BeanInfo. При создании свойств JBuilder спросит, хотите ли вы перекрыть существующие свойства новыми свойствами с такими же именами. Щелкните на кнопке Yes.
Лучше всего следовать соглашению, принятому для большинства Swing-компонентов, и использовать слова foreground и background. Может возникнуть искушение подобрать более информативные имена, например, textColor и Backgrounded or. Но я решил следовать соглашению, предложенному компанией Sun.
Повторите то же для второго свойства с именем background. Добавьте свойство типа int с именем textWidth. После создания свойств не забудьте перейти на закладку BeanInfo и повторно сгенерировать Beanlnfo-файл.
Мы будем использовать свойство textWidth в последующих главах.
Возможно, вам не совсем понравится то, как JBuilder реализует эти методы. Например, я нахожу, что проще реализовать их путем простого вызова соответствующих методов класса-предка. Ниже приведен код, который я набрал самостоятельно, тогда как сгенерированный код я поместил в комментарии.
//private java. awt. Color foreground;
//private java. awt. Color background; public void SetForeground(java. awt. Color foreground)
{
Super. SetForeground(foreground);
//this. foreground = foreground;
I
Public java. awt. Color getForeground()
{
Return super. getForeground();
∕∕ return foreground;
}
Public void SetBackground(java. awt. Color background)
{
Super. SetBackground(background);
//this. background = background;
)
Public java. awt. Color getBackground()
(
Return super. getBackground();
//return background;
)
Вы можете оставить код методов извлечения и присвоения значений в том виде, который они имеют после генерации и который представлен в листинге 35.2. Однако существуют некоторые разногласия по поводу того, какой способ объявления метода Paint Класса ElfCiock Является наилучшим:
Public void paint(Graphics g)
{
//super. paint(g);
G. setColor(this. getBackground());
G. fillRect(O, O, this. getWidth(), this. getHeight()); g. setColor(this. getForeground()); drawClock. draw(g);
}
Как вы наверняка уже заметили, я предпочел закомментировать вызов метода Super.Paint, Так как мы собираемся самостоятельно рисовать весь элемент управления целиком. После этого я устанавливаю значения цвета для компонента и рисую его поверхность с помощью метода fiiiRect.
Приведенный здесь код класса ElfClock Завершается так же, как если бы он все еще рисовал часы, используя компонент JTextField. Однако новая версия компонента Elfciock построена таким образом, чтобы можн’ было достаточно легко расширить и усовершенствовать его функциональность.
Видимость событий нового объекта Clock
Переведите фокус на компонент ElfClock в окне конструктора для класса Framel и перейдите в инспекторе на закладку Events (События). По умолчанию для вашего bean-компонента будут видимы все события, унаследованные им от класса-предка, как показано на рис. 35.13. Здесь логика противоположна той, которая использовалась при работе с SlmpleBeanClass. getAdditionalBeanlnfо.
В главе 33 вы видели, что если метод getʌddi tionalBeanlnf О Возвращал null, а это означало, что сведения о классах-предках недоступны. Здесь мы имеем дело с обратной ситуацией. Если метод getEventSetDescriptors возвращает null, вся информация о событиях, которую можно извлечь из классов-предков, не будет сокрыта, но наоборот, показана.
Прежде чем продолжить, откройте файл EifClockBeaninfor. java и добавьте в него следующий оператор import:
SctionPerformed |
|
AncestorAdded |
|
AncestorMoved |
|
SncestorMoved |
|
SncestorRemoved |
|
SncestorResized |
|
CaretPositionChan. |
|
ComponentAdded _ |
|
ComponentHidden |
|
ComponentMoved |
|
ComponentRemoved |
|
ComponentResized |
|
CqmponentShown |
|
IbcusGained |
|
FocusLost |
|
IiierarchyChanged |
|
InputMethodTe*tCh… |
|
KeyPressed |
|
KeyReleased |
|
Import java. awt. event.*;
Для сокрытия большей части информации о классах-предках переведите фокус на исходный файл ElfClockBeanInfo. java в редакторе JBuilder и введите следующую реализацию метода getEventSetDescriptors:
Public EventSetDescriptor[] getEventSetDescriptors()
{
Try
{
EventSetDescriptor mouse = new EventSetDescriptort ElfClock. class r "MouseListener",
MouseListener. class,
New String[] {"mousePressed", "mouseClicked",
"mouseReleased", "mouseEntered", "mouseExited"},
,,addMouseListener" ,
"removeMouseListener");
EventSetDescriptor eda[] = { mouse } ; return eda;
1
Catch (IntrospectionException e)
{
E. PrintStackTrace();
1
Return null;
1
Этот код указывает на то, что все события, кроме MouseListener, необходимо сокрыть. Первый вызов конструктора для класса EventSetDescriptor остался без изменений. Во втором вызове первым параметром является класс, с которым вы работаете, вторым — имя набора событий, а третьим — интерфейс событий, который вы намерены показать. Четвертый параметр представляет собой имена методов этого интерфейса. Вы можете найти этот список в исходном коде интерфейса MouseListener. Пятый и шестой аргументы — это методы, использующиеся для добавления и удаления интерфейса слушателя.
Результатом вашей работы будет то, что поддерживаться будет ТОЛЬКО интерфейс MouseListener, как показано на рис. 35.14.
Рассмотрим следующий код, но пока не будем набирать его в JBuilder
Public EventSetDescriptor[] getEventSetDescriptors()
{
![]() |
Здесь представлена более простая версия метода getEventSetDescriptors. Она специально предназначена для работы с простыми событиями. Этот код указывает на то, что следует сокрыть все события, кроме событий ActionListener. Ниже Представлены Сведения О КОНСТруКТОре Класса EventSetDescriptor:
■ Первый параметр конструктора класса EventSetDescriptor представляет собой ссылку на класс, с которым вы работаете: Eifcioek. class.
■ Второй параметр — имя набора событий: "ActionListener".
■ Третьим параметром является интерфейс событий, который вы хотите сделать видимым: ActionListener. class.
■ Четвертый параметр — имя единственного метода этого интерфейса: "actionPerformed".
Почти в самом конце метода getEventSetDescriptorβ вы устанавливаете возвращаемое значение, которое представляет собой массив переменных типа EventSGtDescriptor. В данном случае этот массив состоит из одного элемента.
Простой конструктор, используемый в примере ActionEvent, следует применять только для интерфейсов событий, которые содержат единственный метод, а также методы добавления и удаления слушателей, имена которых составлены по стандартному шаблону: addXXX и removeXXX, где XXX — имя интерфейса слушателя событий. Представленный выше интерфейс MouseListener полностью соответствует этому шаблону. Однако сам по себе класс MouseListener не мог бы соответствовать шаблону этого конструктора, так как он содержит слишком много методов. Я не имею в виду, что вы не сможете получить правильный код с помощью этого простого конструктора. Я лишь говорю, что вам не следует пользоваться им, поскольку класс MouseListener содержит чересчур много методов. Вместо этого вам лучше воспользоваться первой верСией конструктора GetEventSetDescriptors, как показано выше.
На рис. 35.15 показано, как все будет выглядеть после того, как вы вставите показанный выше метод GetEventDescriptors, КОТОрЫЙ работает C Классами ActionListener.
Тем не менее, следует отметить, что существует одна существенная проблема, связанная с представленным здесь КОДОМ ActionListener. Наш компонент, ElfClock, Не занимается обработкой событий ActionEvent. Если вы просто попытаетесь вставить код, показанный здесь, в свой Beanlnfo-файл, JBuilder просто проигнорирует метод и будет восстановлено состояние дел, показанное на рис. 35.13 Таким образом, в результате были бы видны все события, принадлежащие как текущему классу, так и классу-предку. Это говорит о том, что мы совершили ошибку. Проблема же состоит в том, чтобы понять, что было сделано некорректно.
Если вы запустили JBuilder из меню запуска KDE, GNOME или Windows, у вас нет возможности узнать, что прошло не так. Однако если вы зайдете в командную строку и запустите JBuilder из оболочки или окна
DOS, то увидите, что при попытке обработать Beanlnfo-класс, содержащий ошибочный код для ActionEvent, JBuilder генерирует исключения и передает их в оболочку или командное окно.
Можно извлечь из этого простой урок: если у вас возникают проблемы с тем, чтобы заставить работать свой BeanInfo-код, запустите JBuilder в режиме командной строки и просмотрите сообщения об исключениях в окне командной строки, которые JBuilder выдает во время компиляции.
Конечно же, существует способ заставить работать методы getEventSetDescriptors экземпляров классов ActionPerformed. Вам потребуется всего ЛИШЬ Добавить ActionEvent в компонент ElfCiock, как показано на рис. 35.16 и как обсуждалось в главах части IIl книги, посвященных обработке событий.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Р JPuHder 7 — G‘.√Src JavaZjbbook <4R∑∕μerιortal∕Cαm∕Eivenv∕βr^Λcomρ∕Cloci‘/FlfCto
Если вы пользуетесь редакцией JBuilder Personal, вам потребуется ввести генерируемый другими версиями код вручную:
Public synchronized void removeActionListener(ActionListener ɪ)
{
If (actionListeners! = null && actIonListeners. contains(1))
<
Vector v β (Vector) actionListeners. clone(); v. removeElement(1,; actionListeners = v;
)
)
Public synchronized void addActionListener(ActionListener 1)
{
Vector v =: actionListeners ==
Null? new Vector (2) : (Vector) actionListeners. clone () ;
If (!v. contains(1))
{
V. addElement(1); actionListeners = v;
}
}
Protected void fIreActionPerformed(ActionEvent e)
{
If (actionListeners! = null)
<
Vector listeners == actionListeners; int count = listeners. size(); for (int i s= O; i < count; i++)
{
((ActionListener) listeners. elementAt(i)).actionPerformed(e);
)
}
}
В том состоянии, в котором в настоящее время находится компонент, нет причины заставлять ElfClock генерировать события ActionPerformed. В данном случае, я делаю это лишь для того, чтобы вы могли лучше понять, как свести вместе все события, описания событий и Beanlnfo-файлы. Однако если хотите, можете расширить компонент ElfClock таким образом, чтобы он выдавал события ActionEvent через определенные интервалы времени. Например, он может генерировать события каждую минуту или через некоторые интервалы, заданные пользователем компонента. Лично мне эта задача кажется простой в реализации, но я не буду загромождать текст этой книги кодом подобного рода, так как это не соответствует нашей теме. Однако я делал неЧто подобное в главах части III, посвященных обработке событий.
Если вы хотите сделать видимым более одного набора событий, воспользуйтесь следующей реализацией метода GetEventSetDescriptor:
Public EventSetDescriptord getEventSetDescriptors()
{
Try
{
EventSetDescriptor action = new EventSetDescriptor(
ElfClock. class, "ActionListener",
ActionListener. class, "actionPerformed");
EventSetDescriptor mouse = new EventSetDescriptor(
ElfClock. class,
"MouseListener",
MouseListener. class,
New String [] {,,mousePressed" , "mouseClicked",
"mouseReleased", "mouseEntered", "mouseE×ited"},
"addMouseListener",
"removeMouseListener");
EventSetDescriptor edλrray[ ] = { action, mouse ) ; return edArray;
}
Catch (IntrospectionException e)
{
E-PrintStackTrace();
}
Return Null;
}
Этот код говорит, что следует сокрыть все события, за исключением событий типа MouseListener И ActionListener.
Обратите внимание на вызов в нижней части метода, в котором осуществляется создание массива переменных типа EventSetDescriptor:
EventSetDescriptor edArray[] = { action, mouse ); Return edArray;
Это как раз то значение, которое возвращает метод.. На рис. 35.17 вы можете посмотреть, какое влияние этот код оказывает на инспектор.
На самом деле, можно еще кое-что сказать об обработке событий. Вы сможете прочесть об этом в главе 37 в разделе, который посвящен BeanInsight.
Рис. 35.17. Внешний вид инспектора для класса в случае использования BeanInfo-файла для сокрытия всех событий за исключением событий ActionListener И MouseListener
Я намереваюсь завершить главу именно здесь не потому, что мы закончили разговаривать о компоненте часов, а просто потому, что наша глава явно затянулась. Вам нужен небольшой перерыв, а также возможность поэкспериментировать с кодом, который вы увидели, прежде чем изучать, что еще можно сделать с компонентом часов.
В этой главе вы изучили принципы работы со свойствами bean-компонентов. В частности, вы увидели, как использовать Beanlnfo-файл для того, чтобы скрывать и показывать свойства своего bean-компонента. Также мы рассмотрели объект Timer И метод Paint.
В следующей главе мы увидим, как добавить дополнительные функции в часы и как преобразовать полученные "часы" в компонент многократного использования, размещенный в JAR-файле.
Чарли Калверт
Глава 36