Читайте также: |
|
Программный интерфейс JavaBeans предоставляет возможности для разработки многократно используемых, встраиваемых, модульных программных компонентов. Такие компоненты обычно используются для решения следующих задач:
· для разработки контейнерных средств приложений (элементов графического интерфейса пользователя GUI, конструкторов приложений application builders и др.), где интерфейс JavaBeans упрощает процессы манипулирования компонентами внутри инструментальных средств. Программа управления компонентами получила название beanbox (контейнер компонентов) и входит в состав пакета JavaBeans Development Kit (BDK);
· для разработки собственных компонентов приложений;
· при использовании нестандартных компонентов, разработанных ранее.
Интерфейс JavaBeans поддерживает ту же модель событий, которая используется в графических пользовательских интерфейсах Swing и AWT. Основной задачей контейнерного приложения является предоставление пользователю возможности настройки компонента путем установки значений свойств. При необходимости задания свойства более сложного типа, используется классы PropertyEditor и Customizer, создающие графический интерфейс для конфигурации и задания значений свойств.
Пример 6.1. Определение пользовательского JavaBeans-компонента, позволяющего отображать несколько строк в статическом элементе Label.
package MultiLineLabel.java;import java.awt.*;import java.util.*; /** * пользовательский компонент, позволяющий размещать * несколько строк текста с заданными отступами и выравниванием **/public class MultiLineLabel extends Canvas { // определяемые пользователем свойства protected String label; // надпись protected int margin_width; // левое и правое поля protected int margin_height; // верхнее и нижнее поля protected Alignment alignment; // выравнивание текста // вычисляемые значения protected int num_lines; // число строк protected String[] lines; // надпись, разбитая на строки protected int[] line_widths; // длина строки protected int max_width; // максимальная длина protected int line_height; // высота шрифта protected int line_ascent; // высота шрифта над базовой линией protected boolean measured = false; // измерение строк // 5 версий конструктора. public MultiLineLabel(String label, int margin_width, int margin_height, Alignment alignment) { this.label = label; // запомнить все свойства. this.margin_width = margin_width; this.margin_height = margin_height; this.alignment = alignment; newLabel(); // разбить надпись на строки. } public MultiLineLabel(String label, int margin_width, int margin_height) { this(label, margin_width, margin_height, Alignment.LEFT); } public MultiLineLabel(String label, Alignment alignment) { this(label, 10, 10, alignment); } public MultiLineLabel(String label) { this(label, 10, 10, Alignment.LEFT);} public MultiLineLabel() { this(""); } // методы установки и опроса атрибутов компонента. public void setLabel(String label) { this.label = label; newLabel(); // деление надписи на строки. measured = false; // запрос на измерение строк. repaint(); // перерисовка. } public void setFont(Font f) { super.setFont(f); // установка нового шрифта. measured = false; // повторное измерение строк. repaint(); // перерисовка. } public void setForeground(Color c) { super.setForeground(c); // новый цвет. repaint(); // перерисовка без изменения размера } public void setAlignment(Alignment a) { alignment = a; repaint(); } public void setMarginWidth(int mw) { margin_width = mw; repaint(); } public void setMarginHeight(int mh) { margin_height = mh; repaint(); } // методы получения значений свойств getFont(), getForeground(), и др. // унаследованы от базового класса. public String getLabel() { return label; } public Alignment getAlignment() { return alignment; } public int getMarginWidth() { return margin_width; } public int getMarginHeight() { return margin_height; } /** * метод вызывается менеджером компоновки для определения желаемого * размера */ public Dimension preferredSize() { if (!measured) measure(); return new Dimension(max_width + 2*margin_width, num_lines * line_height + 2*margin_height); } /** * метод для определения минимального размера места */ public Dimension minimumSize() { return preferredSize(); } /** * метод рисования компонента. **/ public void paint(Graphics g) { int x, y; Dimension size = this.size(); // use getSize() in Java 1.1 if (!measured) measure(); y = line_ascent + (size.height - num_lines * line_height)/2; for(int i = 0; i < num_lines; i++, y += line_height) { if (alignment == Alignment.LEFT) x = margin_width; else if (alignment == Alignment.CENTER) x = (size.width - line_widths[i])/2; else x = size.width - margin_width - line_widths[i]; g.drawString(lines[i], x, y); } } /** * внутренний метод разбивает надпись на массив строк, * используя класс StringTokenizer. **/ protected synchronized void newLabel() { StringTokenizer t = new StringTokenizer(label, "\n"); num_lines = t.countTokens(); lines = new String[num_lines]; line_widths = new int[num_lines]; for(int i = 0; i < num_lines; i++) lines[i] = t.nextToken(); } /** * внутренний метод для определения размеров шрифта, строк **/ protected synchronized void measure() { FontMetrics fm = this.getToolkit().getFontMetrics(this.getFont()); line_height = fm.getHeight(); line_ascent = fm.getAscent(); max_width = 0; for(int i = 0; i < num_lines; i++) { line_widths[i] = fm.stringWidth(lines[i]); if (line_widths[i] > max_width) max_width = line_widths[i]; } measured = true; }}
Пример 6.2. Определяет три константы для выравнивания текста с использованием класса Alignment.
package Alignment.java; /** класс, определяющий перечислимый тип из трех значений */public class Alignment { /** закрытый конструктор, предотвращающий создание экземпляров /** класса */ private Alignment() {}; // три константы, являющиеся единственными экземплярами класса public static final Alignment LEFT = new Alignment(); public static final Alignment CENTER = new Alignment(); public static final Alignment RIGHT = new Alignment();}
Для того чтобы подготовить компонент к использованию в контейнере, его необходимо упаковать вместе с требуемыми ресурсами в файл с расширением JAR (Java archives). Так как один компонент может иметь много вспомогательных файлов, а JAR-файл может содержать несколько компонентов, то должен быть создан манифест JAR-файла, где описывается, какие элементы файла являются компонентами. Для указания того, что файл класса является компонентом, необходимо в элемент манифеста файла добавить следующую строку: Java-Bean: true.
Для установки компонента требуется скопировать JAR-файл с компонентом в каталог jars, находящийся внутри каталога BDK, после чего он будет появляться в палитре компонентов при запуске приложения. Другая возможность состоит в загрузке JAR-файла компонента во время выполнения выбором команды Load JAR в меню File утилиты beanbox.
Пример 6.3. Компонент, отображающий сообщение для пользователя и три кнопки выбора, который часто используется внутри диалоговых окон.
package YesNoPanel.java;import java.awt.*;import java.awt.event.*;import java.util.*; /** * компонент JavaBean для вывода многострочного сообщения и трех кнопок * активизирует AnswerEvent при нажатии одной из них **/public class YesNoPanel extends Panel { // свойства компонента protected String messageText; // сообщение для вывода protected Alignment alignment; // выравнивание protected String yesLabel; // техт для кнопок yes, no, & cancel protected String noLabel; protected String cancelLabel; // внутренние компоненты панели protected MultiLineLabel message; protected Button yes, no, cancel; /** безаргументный конструктор со значениями свойств по умолчанию */ public YesNoPanel() { this("здесь\nВаше\nсообщение"); } public YesNoPanel(String messageText) { this(messageText, Alignment.LEFT, "Yes", "No", "Cancel"); } /** конструктор для использования класса */ public YesNoPanel(String messageText, Alignment alignment, String yesLabel, String noLabel, String cancelLabel) { // создание компонентов панели setLayout(new BorderLayout(15, 15)); // надпись посреди окна message = new MultiLineLabel(messageText, 20, 20, alignment); add(message, BorderLayout.CENTER); // панель для кнопок с размещением внизу компонента, // используя менеджер компоновки FlowLayout. Panel buttonbox = new Panel(); buttonbox.setLayout(new FlowLayout(FlowLayout.CENTER, 25, 15)); add(buttonbox, BorderLayout.SOUTH); // создание кнопок и слушателей событий для них yes = new Button(); // создание кнопок no = new Button(); cancel = new Button(); // размещение их в панели buttonbox.add(yes); buttonbox.add(no); buttonbox.add(cancel); // регистрация слушателей yes.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { fireEvent(new AnswerEvent(YesNoPanel.this, AnswerEvent.YES)); } }); no.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { fireEvent(new AnswerEvent(YesNoPanel.this, AnswerEvent.NO)); } }); cancel.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { fireEvent(new AnswerEvent(YesNoPanel.this, AnswerEvent.CANCEL)); } }); // вызов методов установки свойств сообщений и кнопок setMessageText(messageText); setAlignment(alignment); setYesLabel(yesLabel); setNoLabel(noLabel); setCancelLabel(cancelLabel); } // get-методы для свойств компонента public String getMessageText() { return messageText; } public Alignment getAlignment() { return alignment; } public String getYesLabel() { return yesLabel; } public String getNoLabel() { return noLabel; } public String getCancelLabel() { return cancelLabel; } // set-методы для свойств компонента public void setMessageText(String messageText) { this.messageText = messageText; message.setLabel(messageText); validate(); } public void setAlignment(Alignment alignment) { this.alignment = alignment; message.setAlignment(alignment); } public void setYesLabel(String l) { yesLabel = l; yes.setLabel(l); yes.setVisible((l!= null) && (l.length() > 0)); validate(); } public void setNoLabel(String l) { noLabel = l; no.setLabel(l); no.setVisible((l!= null) && (l.length() > 0)); validate(); } public void setCancelLabel(String l) { cancelLabel = l; cancel.setLabel(l); cancel.setVisible((l!= null) && (l.length() > 0)); validate(); } public void setFont(Font f) { super.setFont(f); // вызов метода базового класса message.setFont(f); yes.setFont(f); no.setFont(f); cancel.setFont(f); validate(); } /** список зарегистрированных ActionListeners */ protected Vector listeners = new Vector(); /** регистрация слушателя действий */ public void addAnswerListener(AnswerListener l) { listeners.addElement(l); } /** удаление слушателя событий Answer */ public void removeAnswerListener(AnswerListener l) { listeners.removeElement(l); } /** посылка события всем зарегистрированным слушателям */ public void fireEvent(AnswerEvent e) { // копия списка с активизацией событий. Vector list = (Vector) listeners.clone(); for(int i = 0; i < list.size(); i++) { AnswerListener listener = (AnswerListener)list.elementAt(i); switch(e.getID()) { case AnswerEvent.YES: listener.yes(e); break; case AnswerEvent.NO: listener.no(e); break; case AnswerEvent.CANCEL: listener.cancel(e); break; } } } /** метод main() для демонстрации класса */ public static void main(String[] args) { // создание InfoPanel с заголовком и сообщением: YesNoPanel p = new YesNoPanel("Вы действительно уверены?"); // регистрируем слушатель событий p.addAnswerListener(new AnswerListener() { public void yes(AnswerEvent e) { System.exit(0); } public void no(AnswerEvent e) { System.out.println("No"); } public void cancel(AnswerEvent e) { System.out.println("Cancel"); } }); Frame f = new Frame(); f.add(p); f.pack(); f.setVisible(true); }}
Пример 6.4. Определение нового класса событий компонентов.
package AnswerEvent.java; /** * класс YesNoPanel активизирует событие при нажатии кнопок * поле id идентифицирует кнопки **/public class AnswerEvent extends java.util.EventObject { public static final int YES = 0, NO = 1, CANCEL = 2; // константы кнопок protected int id; // определение кнопки public AnswerEvent(Object source, int id) { super(source); this.id = id; } public int getID() { return id; } // возвращение кнопки}
Пример 6.5. Определение слушателей событий от компонента YesNoPanel.
package AnswerListener.java; /** * кдассы, заинтересованные в уведомлениях панели * YesNoPanel должны реализовать этот интерфейс. **/public interface AnswerListener extends java.util.EventListener { public void yes(AnswerEvent e); public void no(AnswerEvent e); public void cancel(AnswerEvent e);}
Для работы нашего приложения диалогового окна необходимо использовать все пять классов, являющихся необходимой частью компонента. Дополнительно распространяются и вспомогательные необязательные классы, например, BeanInfo, лредоставляющий дополнительную информацию о компоненте. Класс BeanInfo определяет для компонента несколько информационных частей:
· изображение, представляющее компонент;
· объект BeanDescriptor, содержащий ссылку на класс Customizer;
· список поддерживаемых свойств компонента с кратким описанием;
· метод, возвращающий часто используемое свойство;
· ссылка на класс PropertyEditor для свойств.
Дата добавления: 2015-09-11; просмотров: 71 | Поможем написать вашу работу | Нарушение авторских прав |