Статьи

Как создать клиент веб-службы с помощью Groovy и платформы NetBeans 6.8

В этой статье вы узнаете, как использовать лучшее из Groovy вместе с лучшим из платформы NetBeans . Groovy будет использоваться для доступа к цитатному веб-сервису Шекспира и анализа его полезной нагрузки. Платформа NetBeans будет использоваться для создания модульного графического интерфейса в Swing для взаимодействия через Groovy с веб-службой.

В ходе этой статьи вы познакомитесь со многими классами API NetBeans , такими как TopComponent , Node (в частности, BeanNode и AbstractNode ), BeanTreeView , ExplorerManager , ChildFactory , ProgressHandleFactory и ModuleInstall . На протяжении всего следующего сценария основное внимание будет уделяться классам API-интерфейса NetBeans Lookup , LookupListener и, в частности, InstanceContent . Хотя это никоим образом не является обязательным требованием, вам будет полезно посмотреть сериал10 лучших API-интерфейсов NetBeans, прежде чем продолжить с этой статьей.

содержание

Примечание. Если по какой-либо причине служба цитат Шекспира недоступна во время работы над этой статьей, просто найдите другой веб-сервис где-нибудь в Интернете и затем используйте его, адаптируя приведенные ниже инструкции в случае необходимости.

В конце этой статьи у вас будет приложение, которое выглядит так:

И, загрузив и добавив один новый модуль NetBeans, модуль OfficeLAF и без какой-либо конфигурации или кодирования с вашей стороны, вы сможете доставить приложение, которое выглядит следующим образом:

Если вы застряли в ходе этой статьи, исходный код приложения можно найти здесь:

http://kenai.com/projects/shakespeareannotater/sources/subversion/show

Создание Groovy клиента

В этом разделе мы создадим приложение Java, которое использует Groovy для доступа и анализа нашего веб-сервиса. Приложение Java будет иметь такую ​​структуру:

Сделайте следующие шаги:

  1. Создайте новое Java-приложение с именем «ShakesGroovy». Используйте диалоговое окно «Новый файл» в среде IDE, чтобы добавить новый класс Groovy с именем «ShakesWsClient.groovy» в приложение. Когда вы делаете это, IDE добавляет «groovy-all.jar» в путь к классу приложения и обновляет сценарий сборки, чтобы позволить классу Groovy быть скомпилированным в Java при сборке приложения.
  2. Загрузите полный JAR-файл GroovyWS («groovyws-standalone-xxx.jar») здесь и добавьте его в папку «lib» приложения.
  3. Определите класс Groovy следующим образом:
    package shakesgroovyimport groovyx.net.ws.WSClientclass ShakesWsClient {    String play, speaker, words    void findQuote(searchString){        def proxy = new WSClient("http://www.xmlme.com/WSShakespeare.asmx?WSDL",              ShakesWsClient.class.classLoader)        proxy.initialize()        def speech = new XmlParser().parseText(proxy.GetSpeech(searchString))        play = speech.PLAY.text()        speaker = speech.SPEAKER.text()        words = speech.text()    }}

    В редакторе Groovy в среде IDE, выше должен выглядеть следующим образом : Примечание: Для получения информации о GroovyWS см http://groovy.codehaus.org/GroovyWS для деталей.

  4. Определите класс «Main.java» (на рисунке выше он называется «Demo.java») следующим образом, чтобы вы могли опробовать клиент веб-службы Groovy выше:
    package shakesgroovy;public class Demo {    public static void main(String[] args) {        ShakesWsClient client = new ShakesWsClient();        client.findQuote("fair is foul");        System.out.println(client.getPlay());        System.out.println(client.getSpeaker());        System.out.println(client.getWords());    }}
  5. Запустите приложение. Вы должны увидеть что-то вроде этого как вывод приложения:
    12 Dec 2009 6:45:47 PM org.apache.cxf.endpoint.dynamic.DynamicClientFactory outputDebugINFO: Created classes: com.xmlme.webservices.GetSpeech, com.xmlme.webservices.GetSpeechResponse, com.xmlme.webservices.ObjectFactory12 Dec 2009 6:45:49 PM groovyx.net.ws.AbstractCXFWSClient getBindingOperationInfoWARNING:  Using SOAP version: 1.1MACBETHALLFair is foul, and foul is fair: Hover through the fog and filthy air.
  6. Посмотрите в окне «Файлы», в частности в папке «dist», которую можно увидеть в окне «Файлы» среды IDE NetBeans. Вы должны увидеть два JAR-файла Groovy, а также JAR-файл, содержащий классы Java, созданные в процессе компиляции Groovy:

Как будет объяснено в следующих разделах, три JAR-файла, которые вы видите выше, должны быть заключены в модуль NetBeans, который вы включите в приложение платформы NetBeans, которое вы создадите в следующих разделах. Затем вы создадите новый модуль, который предоставит новое окно в приложении, которое получит доступ к Java-коду (скомпилирован из Groovy выше) для взаимодействия с веб-сервисом Шекспира. Это будет возможно из-за зависимостей, которые вы установите между двумя модулями.

Настройка приложения

Начнем с создания нового приложения на платформе NetBeans.

  1. Выберите «Файл»> «Новый проект» (Ctrl + Shift + N). В разделе «Категории» выберите «Модули NetBeans». В разделе Проекты выберите Приложение платформы NetBeans. Нажмите «Далее.
  2. На панели «Имя и местоположение» введите «ShakespeareSearch» в поле «Имя проекта». Нажмите Готово.

В среде IDE создается проект ShakespeareSearch. Проект является контейнером для всех остальных модулей, которые вы создадите.

Запустите приложение и обратите внимание, что у вас уже есть несколько функций из коробки. Откройте некоторые окна, открепите их и познакомьтесь с основными компонентами, которые предоставляет платформа NetBeans, не выполняя никакой работы:

Примечание. Все, что вы видите на снимке экрана выше, может быть скрыто, если оно избыточно для ваших бизнес-потребностей, или может быть включено, например, можно включить пункт меню «Сохранить», как описано в разделе Как создать приложение Swing CRUD на платформе NetBeans 6.8 .

Как только вы ознакомитесь со структурой вашего приложения (просматривая меню и нажимая кнопки, показанные на снимке экрана выше), перейдите к следующему разделу, в котором вы поместите три Groovy JAR в модуль NetBeans и добавите это к заявке.

Обертывание Groovy-файлов JAR в модуле NetBeans

В этом разделе вы добавляете свой первый модуль в ваше приложение. Новый модуль NetBeans обернет файлы JAR Groovy, с которыми вы работали в первом разделе выше.

  1. Чтобы упростить следующий шаг, поместите три файла JAR («groovy-all.jar», «groovyws-standalone-xxx.jar» и «ShakesGroovy.jar») в одну папку на жестком диске. Как только они окажутся в одной и той же папке, вы сможете выбрать их более просто, с помощью Ctrl-Click в мастере на следующем шаге, когда будете помещать их в модуль NetBeans.
  2. Щелкните правой кнопкой мыши узел «Модули» ShakespeareSearch в окне «Проекты» и выберите «Добавить новую библиотеку». Выберите три JAR-файла («groovy-all.jar», «groovyws-standalone-xxx.jar» и «ShakesGroovy.jar»), нажав «Обзор», а затем «Ctrl-Click», чтобы выбрать все три JAR-файла в папке. где вы положили их выше. Затем завершите работу мастера, указав любые значения, которые вам нравятся, например, заполнив следующие значения:

Теперь у вас есть ваш первый пользовательский модуль в новом приложении, упаковывающий JAR-файлы, содержащие классы, связанные с Groovy. Загляните в узел «Библиотеки» вашего нового модуля NetBeans в окне «Проекты», и вы увидите три JAR-файла:

Щелкните правой кнопкой мыши новый модуль NetBeans, выберите «Свойства», и в узле «Управление версиями API» вы увидите, что все пакеты из трех JAR-файлов в модуле доступны для остальных приложений. Т.е. это пакеты для всего приложения. Это по умолчанию. Однако единственный пакет, который вам нужно предоставить, это последний, т. Е. «Shakesgroovy», потому что это пакет, предоставляющий код Java, скомпилированный из вашего класса Groovy, т. Е. Для взаимодействия с веб-сервисом:

Поэтому, если хотите, вы можете снять галочки для всех других пакетов, перечисленных в диалоговом окне выше, потому что все, что вам нужно представить для остальной части приложения, это пакет «shakesgroovy».

Теперь, когда Groovy JAR доступны в вашем приложении, в следующем разделе будет показано, как вы можете создать новый модуль NetBeans, который будет обращаться к классу Groovy для получения цитат Шекспира из веб-службы. Затем мы потратим некоторое время на создание приятного пользовательского интерфейса, используя множество продвинутых компонентов Swing, которые платформа NetBeans делает доступными бесплатно из коробки.

Создание простого прототипа

Наш простой прототип будет состоять из приложения, содержащего два пользовательских модуля, в дополнение к 5 обязательным модулям платформы NetBeans, составляющим контейнер времени выполнения , а также, опционально, любые другие модули платформы NetBeans, которые вы будете использовать. Первый, который вы создали в предыдущем разделе: он содержит три связанных с Groovy JAR-файла. В этом разделе вы создадите второй модуль. Он предоставит окно через API NetBeans » TopComponent«class, который является JPanel-подобным компонентом, который обеспечивает окна в приложениях платформы NetBeans. В TopComponent у вас будут JLabel, JTextField, JButton и JTextPane. При нажатии кнопки текст в текстовом поле будет отправлен в веб-службу … и ответ будет отображаться в текстовой панели.

  1. Щелкните правой кнопкой мыши узел «Модули» ShakespeareSearch в окне «Проекты» и выберите «Добавить новый». Дайте вашему новому модулю NetBeans имя … … и на следующем шаге укажите уникальный идентификатор для нового модуля NetBeans:
  2. Нажмите Finish, и вы увидите, что в вашем приложении есть два модуля NetBeans:
  3. Теперь мы позволим нашему модулю «ShakesViewer» предоставить окно. Щелкните правой кнопкой мыши проект «ShakesViewer» и выберите «Создать | Другое | Разработка модуля | Компонент окна. Нажмите «Далее. Выберите «редактор» в качестве «Положение окна» и установите флажок «Открыть при запуске приложения». Нажмите «Далее. Введите «ShakesViewer» в «Префикс имени класса» и нажмите «Готово».
  4. Теперь используйте палитру в среде IDE для перетаскивания JLabel, JTextField («searchField»), JButton («findButton») и JTextPane («resultPane») в TopComponent в режиме «Дизайн». Переставляйте компоненты, пока не создадите окно, которое выглядит следующим образом:
  5. Щелкните правой кнопкой мыши приложение и выберите «Выполнить». Приложение запускается, устанавливая все включенные модули платформы NetBeans (чтобы увидеть, что это, щелкните правой кнопкой мыши узел приложения в окне «Проекты», выберите «Свойства» и посмотрите на вкладке «Библиотеки») вместе с двумя пользовательскими модулями. Вы создали до сих пор. Не продолжайте до конца этой статьи, пока не увидите это:
  6. Прежде чем наш второй модуль сможет использовать код Java, предоставленный первым модулем, нам нужно установить зависимость для первого модуля от второго модуля. То есть не только первый модуль должен делать пакеты доступными для всего приложения, но и любое приложение ТАКЖЕ должно устанавливать зависимость от этого первого модуля. Это означает, что у нас есть двунаправленный контракт между модулями в нашем приложении. Щелкните правой кнопкой мыши модуль ShakesViewer, выберите «Свойства» и нажмите «Добавить зависимость» на вкладке «Библиотеки». Затем найдите уникальный идентификатор первого модуля и нажмите «ОК»:
  7. Чтобы мы могли интегрироваться с индикатором выполнения платформы NetBeans (таким образом, обрабатывая сценарий, в котором мы не хотим блокировать пользовательский интерфейс во время взаимодействия с веб-службой), установите другую зависимость, на этот раз с «API-интерфейсом прогресса»:
    Теперь мы готовы начать добавлять код!
  8. В IDE дважды щелкните «findButton», чтобы открыть редактор исходного кода, с курсором в методе «findButtonActionPerformed». Там добавьте этот очень простой фрагмент кода, чтобы получить цитату из веб-службы и отобразить ее в текстовой панели:
    private void findButtonActionPerformed(java.awt.event.ActionEvent evt) {                                               Thread t = new Thread(new Runnable() {        @Override        public void run() {            //Use the NetBeans Progress API to define a new progress handle:            ProgressHandle p = ProgressHandleFactory.createHandle(                    "Fetching the Shakespeare quote for "                    + "'" + searchField.getText() + "'...");            //Start the progress bar:            p.start();            //Find a new Shakespeare quote via the Groovy-based client:            ShakesWsClient client = new ShakesWsClient();            client.findQuote(searchField.getText());            //Populate the UI components with the current object's values:            resultPane.setText(client.getWords());            //Populate the status bar with the Shakespeare play returned:            StatusDisplayer.getDefault().setStatusText("Play: "                     + client.getPlay());            //Finish the progress bar:            p.finish();            //Note: The progress bar takes 3 lines to include,            //and helps us with all UI-blocking activities!        }    });    t.start();}

    Примечание. Подробнее об API-интерфейсе NetBeans читайте здесь .

  9. Запустите приложение и введите в текстовое поле строку поиска, например «love is like»:  нажмите кнопку «Найти». Обратите внимание, что пользовательский интерфейс все еще можно использовать, т. Е. Не блокировать, и что индикатор выполнения дает пользователю обратную связь о происходящей обработке. Как только цитата получена, она появляется в текстовой панели, как показано ниже:

Поздравляю, ваш простой прототип работает как положено. Теперь давайте включим множество интересных и мощных классов API-интерфейса NetBeans, чтобы отобразить полученные результаты в JTree!

Использование компонентов Swing платформы NetBeans

В этом разделе мы добавляем Swing «JTree» в приложение. Однако это будет специальный JTree, который будет лучше интегрироваться с платформой NetBeans, чем стандартный JTree. Это «JTree» — это класс « BeanTreeView » API-интерфейса NetBeans . В конце этого раздела у вас будет «BeanTreeView», в котором будут перечислены колонки, извлеченные из веб-службы, при одновременной синхронизации с окном «Свойства», хотя в окне «Свойства» свойства не будут отображаться, поскольку в этот момент вы будет использовать «AbstractNode» вместо «BeanNode», с которого начнется этот раздел.

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

Кроме того, «BeanTreeView» отображает иерархию «узлов», которые являются объектами платформы NetBeans для визуализации бизнес-объектов. Как правило, в стандартном Swing вам необходимо создать отдельный объект модели для каждого типа компонента Swing, с которым вы работаете (JTree, JTable, JList и т. Д.), В то время как Node является универсальным объектом модели, который работает с любым (версия NetBeans ) из них, таких как «BeanTreeView». Итак, вы создаете свою модель один раз и отображаете ее где угодно.

Эти темы подробно проиллюстрированы в примере кода и текстах, приведенных ниже.

  1. Переключитесь в представление TopComponent Design, щелкните правой кнопкой мыши в палитре, выберите «Диспетчер палитр» | Добавьте из JAR. Затем перейдите к «org-openide-explorer.jar», который находится в папке «platform11 / modules», в установочном каталоге IDE NetBeans. Нажмите Next и выберите «BeanTreeView» и завершите работу мастера. Теперь вы должны увидеть BeanTreeView в палитре. Перетащите его из палитры и поместите в окно слева от текстовой панели. Переместите компоненты и убедитесь, что у вас получилось что-то вроде этого:
  2. Щелкните правой кнопкой мыши узел библиотек «ShakesViewer», выберите «Добавить зависимость модуля», а затем установите зависимости для «API-интерфейсов узлов» и «API-интерфейса Explorer & Property Sheet».
  3. Запустите приложение и убедитесь, что вы видите следующее при запуске:
  4. Затем в исходном коде класса «ShakesViewerTopComponent» измените сигнатуру класса для реализации « ExplorerManager.Provider »:
    final class CustomerTopComponent extends TopComponent implements ExplorerManager.Provider

    Вам нужно будет переопределить «getExplorerManager», чтобы вернуть текущий « ExplorerManager »:

    @Overridepublic ExplorerManager getExplorerManager() {    return em;}

    В верхней части класса объявите и инициализируйте ExplorerManager:

    private static ExplorerManager em = new ExplorerManager();

    Примечание. Посмотрите 10 лучших API NetBeans для получения подробной информации о приведенном выше коде, особенно скринкаст, посвященный API узлов и API Explorer & Property Sheet.

  5. Теперь давайте определим бизнес-объект, который мы будем создавать всякий раз, когда в глобальном « Lookup » будет найден новый объект «ShakesWsClient ».
    public class QuoteBean {        private String name;    private String play;    private String speech;    public String getName() {return name;}    public void setName(String name) {this.name = name;}    public String getPlay() {return play;}    public void setPlay(String play) {this.play = play;}    public String getSpeech() {return speech;}    public void setSpeech(String speech) {this.speech = speech;}}

    Теперь мы будем создавать новые экземпляры этого бизнес-объекта всякий раз, когда новая цитата извлекается из нашего поиска Шекспира и добавляется в глобальный поиск!

  6. Именно в этот момент нам нужно определить объект « ChildFactory », который является классом API NetBeans, который будет генерировать узлы, которые будут отображаться в «BeanTreeView». Итак, создайте новый класс с именем «QuoteChildFactory», который расширяет «ChildFactory», и определите его следующим образом, убедившись, что вы понимаете все комментарии в коде ниже:
    class QuoteChildFactory extends ChildFactory<QuoteBean> implements LookupListener {    private Result<ShakesWsClient> result;    private List<ShakesWsClient> quotes;    public QuoteChildFactory() {        //Listen for ShakesWsClient objects in the global Lookup:        result = Utilities.actionsGlobalContext().lookupResult(ShakesWsClient.class);        result.addLookupListener(this);        //Call once to 'resultChanged' to activate the listener:        resultChanged(new LookupEvent(result));    }    @Override    public void resultChanged(LookupEvent le) {        //Create a new ArrayList:        quotes = new ArrayList();        //Put all the instances of ShakesWsClient found in the global Lookup into a collection:        Collection<? extends ShakesWsClient> coll = result.allInstances();        //Iterate through the collection of found ShakesWsClient objects:        for (ShakesWsClient client : coll) {            //Add all the ShakesWsClient objects in the global Lookup to the ArrayList:            quotes.add(client);            //The list of objects has changed and the Nodes should be updated,            //causing 'createKeys' to be invoked immediately, because of the 'true':            refresh(true);        }    }    @Override    //Whenever a QuoteBean is added to the "quoteBeanList" in this method,    //a call to "createNodeForKey" is triggered, which will receive the QuoteBean:    protected boolean createKeys(List<QuoteBean> quoteBeanList) {        if (!quotes.isEmpty()) {            for (ShakesWsClient client : quotes) {                QuoteBean s = new QuoteBean();                s.setName(client.getSpeaker());                s.setPlay(client.getPlay());                s.setSpeech(client.getWords());                quoteBeanList.add(s);            }        }        return true;    }    //Each time "createNodeForKey" is called,    //which happens when a new QuoteBean is added to the quoteBeanList above,    //a new "Node" is created (see below),    //which wraps the business object and displays it in the explorer view:    @Override    protected Node createNodeForKey(QuoteBean quoteBean) {        try {            return new BeanNode(quoteBean);        } catch (IntrospectionException ex) {            Exceptions.printStackTrace(ex);            return null;        }    }}
  7. В строке 7 выше обратите внимание на этот комментарий: «Прослушивание объектов ShakesWsClient в глобальном поиске». Итак, вопрос, который необходимо решить сейчас: «Как мы добавляем новые объекты ShakesWsClient в глобальный поиск?» Мы делаем это в классе «ShakesViewerTopComponent». Всякий раз, когда создается новый ShakesWsClient, т. Е. Это происходит при получении новой цитаты из веб-службы, нам нужно добавить ее в глобальный поиск. Это позволяет другим частям приложения делать что-то, где это необходимо, т. Е. Дает контекств другие части приложения. В этом случае введение новых ShakesWsClients в глобальный поиск позволяет классу «ChildFactory» создавать новые узлы в «BeanTreeView», поскольку он имеет «LookupListener», который определен для прослушивания присутствия объектов «ShakesWsClient». Так как это сделать? В «ShakesViewerTopComponent» создайте новый экземпляр «InstanceContent»:
    private InstanceContent content = new InstanceContent();

    Затем в конструкторе ShakesViewerTopComponent создайте экземпляр «QuoteChildFactory», а также заполните «Lookup» (т. Е. Контекст) «ShakesViewerTopComponent»:

    //Let the ExplorerManager display new child nodes asynchronously (because of 'true')//in its explorer views (e.g., the BeanTreeView that is defined in this class):em.setRootContext(new AbstractNode(Children.create(new QuoteChildFactory(), true)));//Add the ExplorerManager and the ActionMap to the Lookup of the TopComponent,//together with the InstanceContent:associateLookup(new ProxyLookup(        ExplorerUtils.createLookup(em, getActionMap()),        new AbstractLookup(content)));

    Теперь, когда глобальный поиск «ShakesViewerTopComponent» заполнен (строка 8) кодом синхронизации, позволяющим окну «Свойства» взаимодействовать с представлениями проводника, и (строка 9) «InstanceContent», мы готовы динамически добавлять объекты в » InstanceContent «объект. Итак, наконец, добавьте одну строку («content.add (client)» в строке 14 ниже) к «actionPerformed» объекта «findButton»:

    private void findButtonActionPerformed(java.awt.event.ActionEvent evt) {                                               Thread t = new Thread(new Runnable() {        @Override        public void run() {            ProgressHandle p = ProgressHandleFactory.createHandle(                    "Fetching the Shakespeare quote for "                    + "'" + searchField.getText() + "'...");            p.start();            ShakesWsClient client = new ShakesWsClient();            client.findQuote(searchField.getText());            resultPane.setText(client.getWords());            StatusDisplayer.getDefault().setStatusText("Play: "                    + client.getPlay());            content.add(client);            p.finish();        }    });    t.start();}
  8. Запустите приложение, и вы должны увидеть следующее:

    Переключитесь между двумя возвращенными узлами в «BeanTreeView» и обратите внимание, что окно «Свойства» автоматически обновляется, то есть два представления проводника синхронизируются. Однако «JTextPane» не является представлением обозревателя, поэтому оно не синхронизируется автоматически с представлениями обозревателя. (И теперь вы видите силу представлений проводника в действии!) На следующем шаге вы узнаете, как можно синхронизировать стандартный компонент Swing с представлениями проводника в вашем приложении.

  9. Чтобы синхронизировать «JTextPane» с представлениями проводника, сначала необходимо определить, когда выбран узел в представлении проводника (с помощью мыши и клавиатуры). В то время нам нужно получить текущий «QuoteBean» в локальном «Lookup» «Узла» и использовать этот экземпляр «QuoteBean» для заполнения текстового поля, текстовой панели и строки состояния.
    • Чтобы сделать это, нам нужно создать наш собственный «BeanTreeView», т. Е. Вам нужно создать класс (внутренний класс в «ShakesViewerTopComponent»), который расширяет «BeanTreeView». Внутри этого класса получите события (такие как «MouseClicked» ниже), вызываемые для «JTree» внутри «BeanTreeView». Для этой цели вы можете использовать глобальную переменную «дерево», как показано ниже. Затем получите «ExplorerManager» через представление проводника и определите «QuoteBean», назначенный локальному запросу (то есть локальному контексту) выбранного узла, и используйте этот «QuoteBean» для заполнения текстового поля, текстовой панели и строки состояния. :
      public class MyBTV extends BeanTreeView {    public MyBTV() {        tree.addMouseListener(new MouseAdapter() {            @Override            public void mouseClicked(MouseEvent e) {                //Find the ExplorerManager for this explorer view:                ExplorerManager mgr = ExplorerManager.find(MyBTV.this);                //Get the QuoteBean in the Lookup of the selected Node:                QuoteBean quoteBean = mgr.getSelectedNodes()[0].getLookup().lookup(QuoteBean.class);                if (quoteBean != null) {                    //Update the UI with the current QuoteBean's data:                    resultPane.setText(quoteBean.getSpeech());                    StatusDisplayer.getDefault().setStatusText("Play: " + quoteBean.getPlay());                }            }        });    }}

      Тем не менее, прямо сейчас Поиск узла не содержит «QuoteBean». Это потому, что вы используете BeanNode для определения узла. BeanNode — самый простой из классов Node. Это полезно для быстрого создания прототипов, но не может быть использовано для более сложных сценариев. Например, он не позволяет вам определять контекст (т. Е. «Lookup»). Поэтому откройте «QuoteChildFactory» и создайте пользовательский узел, расширяющий «AbstractNode», где вы передаете новый объект «Lookup», содержащий текущий «QuoteBean», суперклассу:

      public class QuoteNode extends AbstractNode {    protected QuoteNode(QuoteBean quoteBean) {        super(Children.LEAF, Lookups.fixed(quoteBean));        setDisplayName(quoteBean.getName());    }}

      Теперь измените «createNodeForKey» на следующее (то есть, как показано ниже, закомментируйте код «BeanNode» и верните новый «QuoteNode», который вы определили выше):

      //Each time "createNodeForKey" is called, a new "Node" is created,//which wraps the business object and displays it in the explorer view:@Overrideprotected Node createNodeForKey(QuoteBean quoteBean) {    return new QuoteNode(quoteBean);//        try {//            return new BeanNode(quoteBean);//        } catch (IntrospectionException ex) {//            Exceptions.printStackTrace(ex);//            return null;//        }}
    • Наконец, убедитесь, что ваше приложение использует «MyBTV» (определено выше), а не «BeanTreeView» по умолчанию, с которым вы работали ранее. Откройте «ShakesViewerTopComponent» в режиме «Дизайн» (т. Е. В Matisse GUI Builder), щелкните правой кнопкой мыши на текстовой панели, выберите «Настроить код», измените первую строку, как показано ниже, так что «MyBTV» создается, когда ShakesViewerTopComponent будет создан, а затем нажмите кнопку «ОК»: откройте синий блок в редакторе исходного кода и убедитесь, что вы видите это, то есть обратите внимание на «beanTreeView1 = new MyBTV ()» в последней строке ниже:
      private void initComponents() {    jLabel1 = new javax.swing.JLabel();    searchField = new javax.swing.JTextField();    jScrollPane1 = new javax.swing.JScrollPane();    resultPane = new javax.swing.JTextPane();    findButton = new javax.swing.JButton();    beanTreeView1 = new MyBTV();    ...    ...    ...

Запустите приложение еще раз, и у вас не возникнет никаких проблем при выборе другого узла в «BeanTreeView», т. Е. Всякий раз, когда вы выбираете новый «Узел», новый контент будет добавляться к стандартному Swing «JTextPane». (Тем не менее, поскольку теперь вы используете «BeanNode» вместо «AbstractNode», вам необходимо предоставить свои собственные значки и свойства, которые автоматически выполняются «BeanNode», через учебное руководство по API узлов NetBeans .) Запустите приложение еще раз. и вы должны увидеть что-то вроде этого: 

Поздравляем, на данный момент вы использовали некоторые из наиболее важных классов API NetBeans. В следующем (и последнем) разделе мы добавим некоторый дополнительный код, который создаст пользовательский корневой узел (путем создания подкласса «AbstractNode»), а также пункт меню «Удалить» на каждом из дочерних узлов. Последнее позволит удалить элементы в списке, что является типичной функциональностью для этого типа приложений.

Завершение

В этом разделе вы привязываете действие «Удалить» к узлам цитаты. Вы также создаете новый «корневой узел», который заменит используемый по умолчанию «AbstractNode», который вы в настоящее время используете для определения узла, который содержит дочерние узлы (то есть узлы цитаты).

  1. Чтобы определить пункт меню «Удалить» на узлах цитаты, необходимо удалить текущий выбранный узел в «BeanTreeView». Ниже, если нажать OK в диалоговом окне подтверждения, «QuoteBean» будет найден в локальном «Lookup» текущего выбранного «Node». Затем мы используем речь в качестве уникального идентификатора «QuoteBean» (не очень хороший подход, но у нас нет реальных уникальных идентификаторов в этом примере), чтобы идентифицировать соответствующий объект «ShakesWsClient», который мы удаляем из «InstanceContent». ». Следовательно, вам нужно передать InstanceContent в ваш ChildFactory и установить его как переменную класса. С этого момента вы можете использовать «InstanceContent» в своем коде, как это сделано ниже, чтобы удалить «ShakesWsClient»объект из «InstanceContent», после которого воссоздается иерархия узлов.
    private class DeleteAction extends AbstractAction {    private final Node node;    public DeleteAction(String name, Node node) {        super(name);        this.node = node;    }    @Override    public void actionPerformed(ActionEvent e) {        NotifyDescriptor.Confirmation msg = new NotifyDescriptor.Confirmation(                "Are you sure?",                "Delete Quote Item",                NotifyDescriptor.OK_CANCEL_OPTION);        Object result = DialogDisplayer.getDefault().notify(msg);        if (NotifyDescriptor.YES_OPTION.equals(result)) {            QuoteBean quoteBean = node.getLookup().lookup(QuoteBean.class);            for (ShakesWsClient client : quotes) {                if (client.getWords().equals(quoteBean.getSpeech())) {                    content.remove(client);                    refresh(false);                }            }        }    }}

    Примечание. Необходимо установить зависимость от «Dialogs API» платформы NetBeans, которая предоставляет ряд стандартных диалогов, таких как «NotifyDescriptor.Confirmation», которые вы используете в приведенном выше коде, для создания этого диалога:

  2. Теперь мы подключаем вышеуказанное действие к нашему узлу, где передаем метку пункта меню вместе с текущим узлом, чтобы можно было удалить правильный объект из «InstanceContent»:
    public class QuoteNode extends AbstractNode {    protected QuoteNode(QuoteBean quoteBean) {        super(Children.LEAF, Lookups.fixed(quoteBean));        setDisplayName(quoteBean.getName());    }    @Override    public Action[] getActions(boolean bln) {        Action[] actions = new Action[]{            new DeleteAction("Delete", this),};        return actions;    }}
  3. Далее, давайте создадим пользовательский корневой узел, который заменит используемый по умолчанию «AbstractNode». В вашем «TopComponent» определите корневой узел как внутренний класс, убедившись, что у вас есть изображение 16×16 по адресу «/org/shakes/viewer/shakes.png»:
    class RootNode extends AbstractNode {    public RootNode(Children chldrn) {        super(chldrn);        setDisplayName("Speakers");        setIconBaseWithExtension("/org/shakes/viewer/shakes.png");    }}

    А затем используйте «RootNode», определенный выше, при создании дочерних узлов. «ExplorerManager.setRootContext» теперь должен выглядеть следующим образом:

    em.setRootContext(new RootNode(Children.create(new QuoteChildFactory(content), true)));

    Примечание: мы не только используем «RootNode» вместо «AbstractNode», выше мы теперь также передаем «content» (то есть «InstanceContent», определенный в «TopComponent») в объект «ChildFactory», поэтому что мы можем удалить его там, когда это применимо.

  4. Затем удалите вкладку в «TopComponent», так как здесь мы не имеем дело с многодокументным интерфейсом, следовательно, вкладки не нужны. Следуйте инструкциям, приведенным здесь .
  5. При желании в качестве упражнения включите кнопки «Отменить / Повторить», а также функцию «Сохранить», как описано в разделе « Как создать приложение Swing CRUD на платформе NetBeans 6.8» .

Когда вы запустите приложение, вы должны увидеть что-то похожее на это:

Обратите внимание, что отображаемое имя и изображение отображаются вместе с корневым узлом и что, когда вы щелкаете правой кнопкой мыши по дочернему узлу, становится доступным пункт меню «Удалить».

Поздравляем, вы завершили эту статью. Дополнительные руководства см. В учебном курсе по платформе NetBeans .