Студопедия  
Главная страница | Контакты | Случайная страница

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Извлечение BeanInfo с помощью Инспектора

Читайте также:
  1. II. С помощью Мобильных технологий
  2. Trading Techniques Inc. предоставляет месячные, недельные, дневные и почасовые (60 минут) данные по всем фьючерсам с помощью сервиса загрузки данных.
  3. В каких случаях обращаться за ветеринарной помощью
  4. Все элементы состояния можно добавить с помощью вкладки Detail окна спецификации состояния.
  5. Вставка. Ноотропики, или лекарства для ума: можно ли стать гениальным с помощью таблетки?
  6. Выборка, добавление, удаление и обновление данных с помощью SQL-запросов на подсоединенном уровне.
  7. Вычисление площадей плоских фигур с помощью определенного интеграла. Примеры.
  8. Выявление невидимых отпечатков пальцев рук с помощью дактилопорошков
  9. Г) Статистические исследования с помощью диагностических схем
  10. Генерализованное управление с помощью Стимулов.

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

Часть решения ясно видна в конце Главы 12: рефлексия Java позволяет обнаружить все методы анонимных классов. Это совершенное решение проблемы компонента (Bean) без введения любых дополнительных ключевых слов, которые требуются в других визуальных языках программирования. Фактически, одна из главнейших причин добавления рефлексии в Java была в поддержке компонентов (Bean) (хотя рефлексия также поддерживает сериализацию объектов и удаление обращений к методам). Так что вы можете ожидать, что создатель построителя приложения будет рефлектировать каждый компонент (Bean) и охотится за его методами для нахождения свойств и событий для этого компонента (Bean).

Это, конечно, возможно, но разработчики Java хотели обеспечить стандартный инструмент, не только для упрощения использования компонент (Bean), но и для обеспечения стандартного подхода для создания более сложных компонент (Bean). Этим инструментом является класс Introspector, и наиболее важным методом этого класса является static getBeanInfo(). Вы передаете ссылку на Class в этот метод, и он полностью опрашивает этот класс и возвращает объект BeanInfo, который вы можете затем раскрыть для нахождения свойств, методов и србытий.

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

//: c13:BeanDumper.java// Инспектирование Bean.// <applet code=BeanDumper width=600 height=500>// </applet>import java.beans.*;import java.lang.reflect.*;import javax.swing.*;import java.awt.*;import java.awt.event.*;import com.bruceeckel.swing.*; public class BeanDumper extends JApplet { JTextField query = new JTextField(20); JTextArea results = new JTextArea(); public void prt(String s) { results.append(s + "\n"); } public void dump(Class bean){ results.setText(""); BeanInfo bi = null; try { bi = Introspector.getBeanInfo(bean, java.lang.Object.class); } catch(IntrospectionException e) { prt("Couldn't introspect " + bean.getName()); return; } PropertyDescriptor[] properties = bi.getPropertyDescriptors(); for(int i = 0; i < properties.length; i++) { Class p = properties[i].getPropertyType(); prt("Property type:\n " + p.getName() + "Property name:\n " + properties[i].getName()); Method readMethod = properties[i].getReadMethod(); if(readMethod!= null) prt("Read method:\n " + readMethod); Method writeMethod = properties[i].getWriteMethod(); if(writeMethod!= null) prt("Write method:\n " + writeMethod); prt("===================="); } prt("Public methods:"); MethodDescriptor[] methods = bi.getMethodDescriptors(); for(int i = 0; i < methods.length; i++) prt(methods[i].getMethod().toString()); prt("======================"); prt("Event support:"); EventSetDescriptor[] events = bi.getEventSetDescriptors(); for(int i = 0; i < events.length; i++) { prt("Listener type:\n " + events[i].getListenerType().getName()); Method[] lm = events[i].getListenerMethods(); for(int j = 0; j < lm.length; j++) prt("Listener method:\n " + lm[j].getName()); MethodDescriptor[] lmd = events[i].getListenerMethodDescriptors(); for(int j = 0; j < lmd.length; j++) prt("Method descriptor:\n " + lmd[j].getMethod()); Method addListener = events[i].getAddListenerMethod(); prt("Add Listener Method:\n " + addListener); Method removeListener = events[i].getRemoveListenerMethod(); prt("Remove Listener Method:\n " + removeListener); prt("===================="); } } class Dumper implements ActionListener { public void actionPerformed(ActionEvent e) { String name = query.getText(); Class c = null; try { c = Class.forName(name); } catch(ClassNotFoundException ex) { results.setText("Couldn't find " + name); return; } dump(c); } } public void init() { Container cp = getContentPane(); JPanel p = new JPanel(); p.setLayout(new FlowLayout()); p.add(new JLabel("Qualified bean name:")); p.add(query); cp.add(BorderLayout.NORTH, p); cp.add(new JScrollPane(results)); Dumper dmpr = new Dumper(); query.addActionListener(dmpr); query.setText("frogbean.Frog"); // Навязываем определение dmpr.actionPerformed(new ActionEvent(dmpr, 0, "")); } public static void main(String[] args) { Console.run(new BeanDumper(), 600, 500); }} ///:~

BeanDumper.dump() - это метод, который делает всю работу. Сначала он пробует создать объект BeanInfo, и если это происходит успешно, вызывает метод BeanInfo, который производит информацию о свойствах, методах и событиях. В Introspector.getBeanInfo(), вы увидите второй аргумент. Это говорит Introspector, где остановится в иерархии наследования. Здесь он остановится прежде, чем разберет все методы от Object, так как мы не интересуемся ими.

Для свойств: getPropertyDescriptors() возвращает массив из PropertyDescriptor. Для каждого PropertyDescriptor вы можете вызвать getPropertyType() для нахождения класса объекта, который передается и получается через методы свойства. Затем, для каждого свойства вы можете получить псевдоним (получается из имени метода) с помощью getName(), метод для чтения с помощью getReadMethod(), и метод для записи с помощью getWriteMethod(). Последние два метода возвращают объект Method, который может на самом деле использоваться для вызова соответствующего метода объекта (это часть рефлексии).

Для public методов (включая методы свойств) getMethodDescriptors() возвращает массив MethodDescriptor. Для каждого их них вы можете получить ассоциированный объект Method и напечатать его имя.

Для событий getEventSetDescriptors() возвращает массив (как вы думаете, чего?) EventSetDescriptor. Каждый элемент массива может быть опрошен для нахождения класса слушателя, методов класса слушателя и методов добавления (add-) и удаления (remove-). Программа BeanDumper печатает всю эту информацию.

После запуска программа форсирует вычисления frogbean.Frog. То, что получается на выходе, после удаления дополнительных деталей, ненужных здесь, вы видите здесь:

class name: FrogProperty type: ColorProperty name: colorRead method: public Color getColor()Write method: public void setColor(Color)====================Property type: SpotsProperty name: spotsRead method: public Spots getSpots()Write method: public void setSpots(Spots)====================Property type: booleanProperty name: jumperRead method: public boolean isJumper()Write method: public void setJumper(boolean)====================Property type: intProperty name: jumpsRead method: public int getJumps()Write method: public void setJumps(int)====================Public methods:public void setJumps(int)public void croak()public void removeActionListener(ActionListener)public void addActionListener(ActionListener)public int getJumps()public void setColor(Color)public void setSpots(Spots)public void setJumper(boolean)public boolean isJumper()public void addKeyListener(KeyListener)public Color getColor()public void removeKeyListener(KeyListener)public Spots getSpots()======================Event support:Listener type: KeyListenerListener method: keyTypedListener method: keyPressedListener method: keyReleasedMethod descriptor: public void keyTyped(KeyEvent)Method descriptor: public void keyPressed(KeyEvent)Method descriptor: public void keyReleased(KeyEvent)Add Listener Method: public void addKeyListener(KeyListener)Remove Listener Method: public void removeKeyListener(KeyListener)====================Listener type: ActionListenerListener method: actionPerformedMethod descriptor: public void actionPerformed(ActionEvent)Add Listener Method: public void addActionListener(ActionListener)Remove Listener Method: public void removeActionListener(ActionListener)====================

Вот большая часть того, что видит и производит Introspector в качестве объекта BeanInfo для вашего компонента (Bean). Вы можете видеть, что тип свойств и их имена независимы. Обратите внимание на нижний регистр в имени свойства. (Это не случается, когда имя свойства начинается с более чем одной большой буквы в строке.) Запомните, что имена методов, которые вы видите здесь (такие как методы чтения и записи), на самом деле произведены объектом Method, который может быть использован для вызова ассоциированного метода объекта.

Список public методов включает методы, которые не связаны со свойствами или событиями, такие как croak(). Здесь все методы, которые вы можете вызвать программно для компонента (Bean), и построитель приложения может выбрать список всех, когда вы выполняете вызов метода, для облегчения вашей задачи.

Наконец, вы можете видеть события, передающиеся в слушатели, методы слушателей, и методы добавления и удаления слушателей. В общем, так как вы имеете BeanInfo, вы можете найти все, что важно для компонента (Bean). Вы можете также вызвать методы для этого компонента (Bean), даже если у вас нет другой информации, за исключением объекта (опять с помощью рефлексии).

Более изощренные компоненты (Bean)

Этот следующий пример немного более изощренный, хотя фривольный. Есть JPanel, которая рисует маленькую окружность вокруг мыши, куда бы мышь не переместилась. Когда вы нажимаете кнопку, появляется “Bang!” в середине экрана, и возбуждается слушатель события.

Свойства, которые вы можете менять, это размер окружности, точно так же как и цвет, размер и текст слова, которое отображается при нажатии кнопки. BangBean также имеет свой собственный addActionListener() и removeActionListener(), так что вы можете присоединять свой собственный слушатель, который будет обрабатывать щелчки мыши в BangBean. Вы должны быть способны распознать свойства и поддержку событий:

//: bangbean:BangBean.java// Графический Bean.package bangbean;import javax.swing.*;import java.awt.*;import java.awt.event.*;import java.io.*;import java.util.*;import com.bruceeckel.swing.*; public class BangBean extends JPanel implements Serializable { protected int xm, ym; protected int cSize = 20; // Размер окружности protected String text = "Bang!"; protected int fontSize = 48; protected Color tColor = Color.red; protected ActionListener actionListener; public BangBean() { addMouseListener(new ML()); addMouseMotionListener(new MML()); } public int getCircleSize() { return cSize; } public void setCircleSize(int newSize) { cSize = newSize; } public String getBangText() { return text; } public void setBangText(String newText) { text = newText; } public int getFontSize() { return fontSize; } public void setFontSize(int newSize) { fontSize = newSize; } public Color getTextColor() { return tColor; } public void setTextColor(Color newColor) { tColor = newColor; } public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.black); g.drawOval(xm - cSize/2, ym - cSize/2, cSize, cSize); } // Это уникальный слушатель, который // является упрощенной формой управления слушателем: public void addActionListener (ActionListener l) throws TooManyListenersException { if(actionListener!= null) throw new TooManyListenersException(); actionListener = l; } public void removeActionListener(ActionListener l) { actionListener = null; } class ML extends MouseAdapter { public void mousePressed(MouseEvent e) { Graphics g = getGraphics(); g.setColor(tColor); g.setFont(new Font("TimesRoman", Font.BOLD, fontSize)); int width = g.getFontMetrics().stringWidth(text); g.drawString(text, (getSize().width - width) /2, getSize().height/2); g.dispose(); // Вызов метода слушателя: if(actionListener!= null) actionListener.actionPerformed(new ActionEvent(BangBean.this, ActionEvent.ACTION_PERFORMED, null)); } } class MML extends MouseMotionAdapter { public void mouseMoved(MouseEvent e) { xm = e.getX(); ym = e.getY(); repaint(); } } public Dimension getPreferredSize() { return new Dimension(200, 200); }} ///:~

Первое, что вы заметите, это то, что BangBean реализует интерфейс Serializable. Это значит, что построитель приложения может “законсервировать” всю информацию для BangBean, используя сериализацию, после того, как дизайнер установит значения свойств. Когда компонент (Bean) создастся как часть работающего приложения, эти “законсервированные” свойства восстанавливаются, так что вы получаете точно то, что разрабатывали.

Вы можете видеть, что все поля являются private, это то, что вы обычно делаете с компонентами, позволяя получить доступ только через методы, обычно, используя схему “property”.

Когда вы взглянете на сигнатуру addActionListener(), вы увидите, что он может выбрасывать TooManyListenersException. Это означает, что здесь индивидуальная (unicast) обработка, которая означает, что извещается только один слушатель о возникновении события. Обычно вы будете использовать групповые (multicast) события, так что много слушателей могут быть извещены о событии. Однако это вводит нас в область, которую вы не готовы воспринять до следующей главы, так что мы вернемся к этому (под заголовком “возврат к JavaBeans”). Индивидуальная обработка обходит проблему.

Когда вы щелкаете мышью, текст помещается в центр BangBean, а если поле actionListener не null, вызывается actionPerformed(), в процессе создается новый объект ActionEvent. Куда бы мышь не переместилась, захватываются новые координаты, и происходит перерисовка канвы (стирание любого текста, расположенного на канве, как вы увидите).

Здесь приведен класс BangBeanTest, позволяющий вам проверить компонент либо как апплет, либо как приложение:

//: c13:BangBeanTest.java// <applet code=BangBeanTest // width=400 height=500></applet>import bangbean.*;import javax.swing.*;import java.awt.*;import java.awt.event.*;import java.util.*;import com.bruceeckel.swing.*; public class BangBeanTest extends JApplet { JTextField txt = new JTextField(20); // Во время тестирования отчет о действиях: class BBL implements ActionListener { int count = 0; public void actionPerformed(ActionEvent e){ txt.setText("BangBean action "+ count++); } } public void init() { BangBean bb = new BangBean(); try { bb.addActionListener(new BBL()); } catch(TooManyListenersException e) { txt.setText("Too many listeners"); } Container cp = getContentPane(); cp.add(bb); cp.add(BorderLayout.SOUTH, txt); } public static void main(String[] args) { Console.run(new BangBeanTest(), 400, 500); }} ///:~

Когда компонент (Bean) находится в среде разработки, этот класс не будет использоваться, но полезно обеспечить тестирование метода для каждого вашего компонента (Bean). BangBeanTest помещает BangBean в апплет, присоединяет простой ActionListener к BangBean для печати счетчика событий в JTextField, когда бы не возникло ActionEvent. Конечно, обычно построитель приложения создает большинство кода, который использует этот компонент (Bean).

Когда вы запустите BangBean через BeanDumper, или поместите BangBean внутрь среды разработки, поддерживающей компоненты, вы заметите, что есть гораздо больше свойств и действий, чем это видно в приведенном выше коде. Это происходит потому, что BangBean наследуется от JPanel, а JPanel - это тоже компонент (Bean), так что вы также видите его свойства и события.




Дата добавления: 2015-09-11; просмотров: 20 | Поможем написать вашу работу | Нарушение авторских прав

Окна сообщений | Всплывающие меню | Окна диалогов | Файловые диалоги | Деревья | Таблицы | Буфер обмена | Динамическое построение событий | Отделение бизнес логики от логики пользовательского интерфейса | Каноническая форма |


lektsii.net - Лекции.Нет - 2014-2024 год. (0.009 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав