Материал: Портянкин И. Swing

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

10

ГЛАВА 1

private Color color;

Затем нужно написать два метода для считывания и записи этого свойства:

public Color getColor() { /* … */ } public void setColor(Color c) { /* … */ }

Когда средство разработки программ при анализе вашего класса обнаружит пару этих методов, оно добавит в список свойств вашего компонента свойство color, и разработчик, использующий ваш компонент, сможет менять это свойство. Можно даже предоставлять только метод для считывания (getXxx()) и таким образом помечать свойство компонента как предназначенное только для чтения. Заметьте, что имена методов должны следовать рекомендациям Sun, поэтому после слов get или set наличие прописной буквы обязательно.

2.Если какое-то свойство компонента имеет булев тип (boolean), можно использовать альтернативный вариант именования метода для получения значения этого свойства. Например, рассмотрим свойство вида:

private boolean enabled;

Методы для этого свойства могут иметь следующие названия:

public boolean isEnabled() { /* ... */ } public void setEnabled(boolean b) { /* ... */ }

То есть метод для записи нового значения не меняется, в методе для получения значения вместо приставки get используется is. Это сделано исключительно для того, чтобы людям было проще читать названия таких методов.

3.Методы компонента, которые не предназначены для считывания и записи свойств, но служащие для выполнения каких-то важных действий, должны быть объявлены открытыми (public).

4.Для каждого события, которое способен генерировать компонент, необходимо предоставить пару методов для добавления и удаления объектов, заинтересованных в этом событии (эти объекты называют слушателями). Мы подробнее разберемся с событиями чуть позже, в главе 2.

5.Класс компонента необходимо объявить открытым (public) и определить в нем конструктор без параметров. Тогда средство разработки программ сможет создать экземпляр такого класса, не обладая дополнительной информацией о типе и предназначении параметров, передающихся в конструкторе. Если вашему компоненту все же нужны параметры для корректной работы, всегда можно сделать их свойствами и предоставить в классе методы для считывания и записи значений этих свойств.

В результате мы получим класс, единственное отличие которого от других классов состоит в том, что его методы следуют стандартной схеме именования JavaBeans. Этого будет вполне достаточно для того, чтобы средство визуальной разработки приложений смогло распознать в нем компонент и вывести список его свойств и событий. Только вдумайтесь, насколько просто звучит такое утверждение и какие у него потрясающие последствия. Вы создаете обычный класс, называя методы по незамысловатым правилам, компилируете его, после чего класс становится доступным для всего мира, причем использовать его можно как угодно — достаточно просто создать объект в своей программе и настроить в визуальном средстве или в распределенном окружении так, как вам нужно.

Основные концепции

11

Архитектура JavaBeans стала настоящим открытием в компонентном программировании и придала ему новый импульс. С ее появлением отпала необходимость изучать дополнительные библиотеки и разрабатывать сопровождающие программы только для того, чтобы построить компонент. Вы строите компоненты, просто создавая классы, что вместе с переносимостью Java дает программисту очень большие возможности. Неудивительно, что после выхода пакета JDK 1.1 и появления в нем спецификации JavaBeans началось настоящее «извержение» компонентов от разных производителей. Более того, создатели Java переделали многие классы стандартных библиотек так, чтобы они удовлетворяли требованиям новой архитектуры. Сейчас представить себе Java без JavaBeans уже невозможно: все связанные с платформой технологии и спецификации используют JavaBeans.

Кроме того что технология JavaBeans дает возможность работать визуальным средствам с любыми компонентами от любых производителей, она может быть полезна и при «ручном» написании программ. Зная набор простых правил, которым подчиняются названия методов любого компонента, можно предположить, каким свойством обладает компонент, и вызывать соответствующие этому свойству методы, не обращаясь к документации или тратя на ознакомление с ней минимум времени. Если создатели компонента удачно подбирают названия его свойств, знакомство программиста с таким компонентом проходит быстро и безболезненно (компоненты библиотеки Swing — прекрасный пример).

Расширенные возможности

Архитектура JavaBeans не ограничивается соглашением об именах и новой системой событий, и предоставляет программисту дополнительные способы настройки и расширения своих компонентов. В их числе можно назвать привязанные и ограниченные свойства, собственные редакторы свойств, дополнительные описания компонентов и многое другое. Чтобы получить представление о возможностях JavaBeans, обсудим эти возможности, не вдаваясь в детали, а подробности всегда можно узнать в интерактивной документации Java.

Привязанные свойства

Привязанные (bound) свойства используются в тех случаях, когда о смене значения свойства необходимо сообщить другому компоненту или объекту. В пакете java.beans имеются несколько вспомогательных классов, позволяющих реализовать привязанные свойства без особых усилий. Все сводится к тому, что в классе компонента появляется еще одна пара методов для добавления и удаления слушателей события типа PropertyChangeEvent, однако событие это не относится к работе компонента, а возникает при смене значения некого свойства. Заинтересованным в смене значения свойства объектам нужно лишь следить за этим событием. При обработке события можно узнать, какое свойство изменилось, каким стало новое значение этого свойства, каким было его старое значение. Свойства почти всегда делают привязанными, по нескольким причинам. Во-первых, визуальные средства разработки часто используют этот механизм, чтобы контролировать, когда следует обновлять внешний вид компонентов и список свойств, ну а во-вторых, сами компоненты следят за состоянием своих или чужих свойств, чтобы выглядеть или вести себя соответственно.

Ограниченные свойства

Ограниченные (constrained) свойства помогают контролировать правильность смены свойств компонента в визуальном средстве разработки. Для реализации ограниченных свойств в класс компонента добавляются методы, позволяющие добавлять и удалять слушателей типа VetoableChangeListener. При смене значения ограниченного свойства этим слушателем посылается запрос, они проверяют, можно ли установить

12

ГЛАВА 1

новое значение свойства, и если новое значение не подходит, возбуждают исключение PropertyVetoException. Визуальное средство при возникновении такого исключения сообщает пользователю, что введенное им новое значение свойства применять нельзя.

Индексированные свойства

Бывают ситуации, когда использовать обычные свойства и методы для работы с ними не совсем удобно, например, если компонент хранит множество однотипной информации (список). В JavaBeans специально для этого предусмотрены индексированные (indexed) свойства. Отличие их от обычных свойств заключается в том, что вместо одного объекта в методах set/get передается массив объектов, и в дополнение к этим двум методам предоставляются методы, изменяющие одну из позиций в этом массиве. Выглядеть это может так:

public Color[] getColors(); public void setColors(Color[] c); public Color getColors(int index);

public void setColors(int index, Color c);

Здесь имя индексированного свойства — colors, и для него предоставлено по 2 метода get/set. Первая пара методов манипулирует списком целиком, вторая позволяет менять одну из позиций списка. Индексированные свойства могут быть привязанными и ограниченными, так же как обычные.

Редакторы свойств

По умолчанию считается, что визуальное средство разработки способно обеспечить правильное редактирование свойств. Для наиболее часто встречающихся свойств так оно и есть (любое средство справится со свойствами, заданными в виде строк, чисел или цветов). Однако если ваш компонент обладает свойством неизвестного и довольно сложного типа, визуальное средство не сможет помочь программисту, и ему придется настраивать ваш компонент вручную, что вообще-то противоречит принципу визуального программирования. Архитектура JavaBeans решает эту проблему с помощью редакторов свойств (property editors). Редактор свойств — это дополнительный компонент, позволяющий настраивать свойства определенного типа, он чаще всего поставляется вместе с компонентом. Создать его довольно просто — надо расширить класс PropertyEditorSupport, написать на его основе редактор свойств и зарегистрировать его. Проще всего зарегистрировать редактор с помощью класса PropertyEditorManager из пакета java.beans. Статический метод registerEditor() этого класса позволяет сопоставить тип свойства и класс его редактора.

Описание компонента

Если средство разработки исследует компонент, опираясь только на соглашение об именах, то у него оказывается минимум информации (названия свойств и событий, используемых в классе компонента, и ничего больше). Иногда этого мало, и в таких случаях для компонентов придется писать подробную документацию с описанием каждого свойства, события и их действия. В JavaBeans предусмотрен механизм, называемый описанием компонента (bean info), который дает возможность ассоциировать с компонентом дополнительную информацию о его свойствах и событиях. Этот механизм позволяет создателю компонента точно указать, как должно называться свойство или событие (совпадение с названиями в коде не обязательно), кратко описать его предназначение, отделить обычные свойства от свойств, контролирующих более сложные аспекты работы компонента.

Основные концепции

13

Для того чтобы создать описание компонента, необходимо определить класс со специальным именем: имя класса компонента плюс слово «BeanInfo». Этот класс должен либо реализовывать интерфейс BeanInfo, либо расширять класс SimpleBeanInfo (который также реализует интерфейс BeanInfo и служит для упрощения реализации этого интерфейса). Реализуя методы интерфейса BeanInfo, программист может весьма подробно описать свой компонент. Затем полученный класс упаковывается в архив вместе с компонентом, и средство разработки, загружая этот архив, извлекает дополнительную информацию о компоненте.

Постоянство

При работе с компонентом программист меняет его свойства и пишет код, обрабатывающий события. Эти изменения отражаются средством быстрой разработки в коде создаваемой программы: по мере необходимости оно генерирует код, который после компиляции и запуска программы приведет компонент к нужному состоянию. Однако такой подход не всегда удобен и не всегда возможен, например, если информация внутри компонента очень важна или смена состояния посредством вызова методов занимает слишком много времени и памяти (наиболее вероятна такая ситуация при удаленном вызове методов компонента).

Поэтому в компонентном программировании появилось понятие постоянства (persistence). Говорят, что компонент поддерживает постоянство, если он обладает способностью вынести свое состояние во внешнее хранилище (файл или базу данных), а после при необходимости восстановить его.

Поначалу архитектура JavaBeans поддерживала постоянство посредством встроенного в Java механизма сериализации (serialization). Суть этого механизма состоит в том, что объект, реализующий интерфейс Serializable, может быть представлен в двоичной форме (фактически производится побитовое копирование полей объекта). Поэтому для компонентов рекомендовалось реализовывать интерфейс Serializable на тот случай, если придется хранить свое состояние во внешней среде. Однако такой подход не всегда обеспечивает хороший результат — сериализованные объекты без специальных усилий (серийных номеров) несовместимы друг с другом (из-за любых, даже минимальных, изменений в классе объекта или в виртуальной машине), формат сериализованных данных неудобен для чтения в случае отладки или локализации приложения.

С появлением JDK 1.4 нашлось еще одно весьма достойное решение. В этом пакете разработки состояние компонента стало возможным хранить в файле формата XML. К очевидным преимуществам нового подхода следует отнести то, что сохраняется не детализированная информация о компоненте, а лишь минимальная последовательность действий, необходимая для приведения компонента в нужное состояние. Это решение вполне может обеспечить необходимую степень совместимости, простоты и переносимости. Учитывая популярность XML (Extension Markup Language — расширенный язык разметки) и разнообразие средств для работы с этим универсальным языком, можно сказать, что компоненты JavaBeans имеют приличный механизм обеспечения постоянства. Новый механизм поддерживается классами XMLEncoder и XMLDecoder из пакета java. beans. Данные классы неплохо документированы, практически все их действия легко переопределить в соответствии со своими нуждами, а на сайте Sun/Oracle вы найдете немало дополнительной информации о них.

Компоненты Swing — это компоненты JavaBeans

Теперь, когда мы увидели, как много привнесла в Java спецификация JavaBeans, нетрудно догадаться, что библиотека Swing проектировалась в полном соответствии с ней. Классы библиотеки Swing, представляющие собой компоненты, созданы в соответствии с соглашением об именах. Все возможности компонентов Swing представлены в виде свойств

14

ГЛАВА 1

и имеют соответствующий набор методов get/set. События компонентов также используют схему JavaBeans. Поддерживается и новый механизм постоянства (на основе XML).

Однако компоненты Swing не злоупотребляют возможностями JavaBeans и реализуют лишь то, что действительно необходимо для работы (эта библиотека специально разрабатывалась в расчете на то, что ей будет максимально просто пользоваться). Все свойства компонентов являются привязанными (это действительно удобно и позволяет легко узнавать об изменениях в компоненте), однако ограниченных свойств, требующих к себе повышенного внимания, в библиотеке почти нет (их всего несколько, и все они сосредоточены в классе внутренних окон JInternalFrame). Индексированных свойств также немного (вместо них рекомендуется использовать модели, о которых мы еще поговорим). Описания компонентов в Swing есть, но обычно эти описания требуются только в визуальных средствах. И вообще при применении библиотеки не чувствуется, что компоненты спроектированы согласно архитектуре JavaBeans и могут свободно использоваться в визуальных средствах — с ними одинаково просто работать и как с визуальными компонентами, и как с обычными классами.

То, что компоненты Swing являются компонентами JavaBeans, важно скорее для средств RAD, для любого из которых сейчас характерна полная поддержка Swing. В этой книге мы не рассматриваем вопросы и проблемы визуального программирования, однако знание JavaBeans иногда оказывается очень удобным. Создателям Swing удалось удачно подобрать названия свойств компонентов, и при написании программы зачастую удается просто угадывать названия нужных методов. Например, довольно очевидно, что у текстового поля (JTextField) должны быть свойства «текст» (text), имея в виду весь напечатанный текст, и «выделенный текст» (selected text). Для получения значения этих свойств можно попытаться вызвать методы getText() и getSelectedText(). Как оказывается, методы именно с такими именами присутствуют в классе JTextField. Зная методы для получения значений свойств, легко понять, какие методы используются для изменения свойств: setText() и setSelectedText(). Вы будете приятно удивлены тем, как часто срабатывает в Swing такой трюк, и как это ускоряет работу. Конечно, это не рецепт на все случаи жизни, но, по крайней мере, методы с такими понятными названиями и запоминать гораздо проще.

Подключаемые внешний вид и поведение

Обсуждая библиотеку AWT, мы выяснили, что компоненты этой библиотеки не отвечают за свой внешний вид на экране. Их помощники направляют запросы к операционной системе, которая и обеспечивает появление на экране элементов управления. Благодаря этому внешний вид Java-приложений и обычных приложений для конкретной операционной системы не должен отличаться (по крайней мере, в теории). Увы, это не совсем так. Виртуальные машины Java от разных производителей даже на единственной платформе вполне могут придать AWT-приложениям различающийся внешний вид, похожий на что угодно, но только не на приложения, к которым привык пользователь платформы.

Когда стало окончательно ясно, что компоненты AWT хоть и работают, но обеспечить более или менее приличный интерфейс не могут (по крайней мере, без дополнительных усилий), взоры обратились в сторону легковесных компонентов. Мы уже знаем, что легковесные компоненты не зависят от платформы и полностью находятся во власти Java-приложения. Это прекрасно, но здесь есть ловушка. Кто-то должен обеспечить им нужный внешний вид и взаимодействие с пользователем. Операционная система больше не участвует в создании компонентов, и получается, что разработчику компонента нужно делать все самому, начиная от подбора цветов и заканчивая поддержкой клавиатуры.

Пока библиотека Swing находилась на ранней стадии разработки, появились первые библиотеки легковесных компонентов от сторонних производителей. Создатели этих библиотек пошли по пути наименьшего сопротивления — прорисовка компонентов и их поведение записывались в один класс. С одной стороны, было понятно, что каждый компонент

Источник: https://studfile.net/preview/15935977/