В этой части мы сделаем важный шаг. Мы пойдем из этой позиции ( на этом предыдущая статья закончилась):
… к этому:
Наше приложение будет по-прежнему только для просмотра, т. Е. Без функции редактирования. (Это будет следующая часть, где большая пустая область на снимке экрана выше станет нашим редактором.) Однако вместо JTable у нас будет представление обозревателя платформы NetBeans. На самом деле их будет два: древовидное представление в левом верхнем углу — это BeanTreeView , а нижнее левое представление — в окне свойств платформы NetBeans. Одним из преимуществ использования этих двух представлений вместо JTable является то, что они автоматически синхронизируются. Без необходимости предоставлять какой-либо код, мы позволим окну Свойства отражать то, что выбрано в BeanTreeView.
Другим важным изменением является то, что мы не будем использовать Beans Binding для сопоставления результата запроса JPA с JTable. Вместо этого мы будем использовать типичный подход платформы NetBeans: класс узла NetBeans . Узлы NetBeans широко распространены в приложениях платформы NetBeans. Это общие иерархические экранные объекты, которые мы будем использовать для представления нашего класса сущностей JPA. Имея узел NetBeans, представляющий нашу сущность JPA, мы даем возможность отображать данные клиента в представлениях проводника. Почему как? Потому что просмотрщик (например, BeanTreeView) существует только для отображения узлов NetBeans. Кроме того, узел NetBeans создаст слой между нашим классом сущностей и представлением обозревателя, что также является хорошей вещью, дополнительно отделяя (и формализуя разделение) наши данные от нашего представления.
Давайте начнем.
- Делайте все, как указано в предыдущей статье. Выполните все шаги в Hello EclipseLink + BeansBinding на платформе NetBeans . В конце у вас будет приложение с 4 модулями, отображающее данные из базы данных в JTable, а JTextFields показывает детали. JTable и JTextFields используют Beans Binding для соединения их с данными.
- Создать узел. Теперь давайте приступим к делу. Нам нужен узел NetBeans, который (1) будет представлять наш класс сущности «Клиент» и (2) будет предоставлять функции отображения на уровне пользовательского интерфейса (такие как отображаемое имя, значок, щелчок правой кнопкой мыши по элементам контекстного меню и синхронизация листа свойств). Первое, что нам нужно сделать, это установить зависимость от Nodes API (щелкните правой кнопкой мыши модуль «Viewer-UI», выберите «Свойства», затем выберите «Библиотеки» и перейдите к «Nodes API»). Ура, теперь вы можете создать свой первый Node, потому что у нас теперь есть модуль, который предоставляет класс Node в нашем модуле classpath. Вот как мы будем создавать наши узлы с помощью класса NetBeans ChildFactory (например, создайте класс, который вы видите ниже, в модуле «Viewer-UI» вашего приложения):
public class CustomerChildFactory extends ChildFactory<Customer> {
private List<Customer> list;
CustomerChildFactory(List<Customer> list) {
this.list = list;
}
@Override
protected boolean createKeys(List<Customer> keys) {
for (Customer c : list) {
keys.add(c);
}
return true;
}
@Override
protected Node createNodeForKey(Customer c) {
return new CustomerNode(c.getName());
}
private class CustomerNode extends AbstractNode {
private CustomerNode(String customerName) {
super(Children.LEAF);
setDisplayName(customerName);
}
}
}Вот оно Что тут происходит? Во-первых, когда класс создается, мы передаем список клиентов. («Клиент» — это наш класс сущностей, расположенный в другом модуле, но легко доступный через управление зависимостями между модулями.) Затем мы создаем переменную класса, чтобы Список клиентов можно было использовать в другом месте класса. «CreateKeys» переопределяется. Всякий раз, когда вызывается «keys.add», вызывается «createNodeForKey», который, в свою очередь, создает новый узел для текущего клиента. Каждый узел имеет только отображаемое имя. Кроме того, мы можем видеть, что каждый узел является дочерним узлом, а не узлом, который содержит своих собственных потомков. Это все. Вот как создаются наши узлы.
- Создайте контроллер контекста. Теперь нам нужно как-то создать экземпляр вышеупомянутого класса. Как это сделать? Откройте «ViewerTopComponent» в представлении «Источник». Измените подпись класса следующим образом:
final class ViewerTopComponent extends TopComponent implements ExplorerManager.Provider
Теперь вы должны увидеть сообщение об ошибке, потому что вам нужно установить другую зависимость. Эта зависимость (как в предыдущем диалоговом окне «Свойства проекта») должна быть в «Проводнике и API-интерфейсе листа свойств». После того, как вы установили эту зависимость, вы можете позволить IDE добавить требуемый оператор импорта. Кроме того, вам будет предложено разрешить IDE реализовать этот метод:
public ExplorerManager getExplorerManager() {
return em;
}Объявите и инициализируйте менеджер Explorer в верхней части класса, например:
private ExplorerManager em = new ExplorerManager();
Теперь, что ты сделал? Вы реализовали класс NetBeans ExplorerManager . Этот класс обрабатывает контекст представлений проводника для вас. Так, например, если у вас есть несколько представлений обозревателя (таких как BeanTreeView и лист свойств, как показано на снимках экрана выше), Диспетчер проводников будет синхронизировать эти два, так что выбранный клиент в одном представлении также будет выбран во всех других представлениях, которые используют тот же диспетчер проводников Другими словами, Диспетчер проводников является вашим дружественным контекстным контроллером, который заботится о низкоуровневой сантехнике, необходимой для обеспечения синхронизации выбора между представлениями проводника. Удобно, правда?
- Показать узел. Теперь, как мы отображаем наш Узел и, таким образом, класс сущности, который представляет Узел? Вот так в конструкторе «ViewerTopComponent»:
em.setRootContext(new AbstractNode(Children.create(new CustomerNode(list), true)));
em.getRootContext().setDisplayName("All Customers");Итак, мы позволяем Диспетчеру проводников обрабатывать отображение нашего узла. Диспетчер проводников будет искать иерархию компонентов для любого компонента Swing, с которым он может взаимодействовать. Есть ли в нашем приложении какие-либо из компонентов Swing? Нет, нет Так что, если бы вы запустили приложение прямо сейчас, ничего бы не отображалось.
Поэтому нам нужны некоторые из этих специальных компонентов Swing, которые называются «представления обозревателя». Щелкните правой кнопкой мыши в палитре, выберите «Диспетчер палитр», нажмите «Добавить из JAR», а затем перейдите к «org-openide-explorer.jar», который находится в вашем дистрибутиве IDE NetBeans (в «platform9 / modules»). Затем нажмите «Далее» и выберите «BeanTreeView». Добавьте его к любой из категорий в палитре, затем перетащите его из палитры на верхний компонент. Запустите приложение, и вы увидите, что BeanTreeView отображает ваши узлы через диспетчер проводников, который является посредником между Node и BeanTreeView.
- Синхронизировать с окном свойств. Если вы запустите приложение, а затем откроете окно свойств, вы не увидите ничего особенного. Тем не менее, добавьте немного волшебства где-нибудь в конструктор TopComponent, и тогда все будет выглядеть по-другому:
ActionMap map = getActionMap();
associateLookup(ExplorerUtils.createLookup(em, map));Запустите приложение еще раз, откройте окно «Свойства» и обратите внимание, что в нижней части вкладки отображается то же имя, которое выбрано в данный момент в древовидном представлении.
Теперь, в определении вашего «CustomerNode», определите несколько свойств и добавьте их в окно «Свойства» для текущего узла:
@Override
protected Sheet createSheet() {
Sheet sheet = Sheet.createDefault();
Sheet.Set propertiesSet = Sheet.createPropertiesSet();
Sheet.Set expertSet = Sheet.createExpertSet();
Property normalProperty;
Property expertProperty;
normalProperty = new PropertySupport.ReadOnly<java.lang.String>(key.getCity(), java.lang.String.class, "City", "The city of " + key.getCity()) {
public java.lang.String getValue() {
return key.getCity();
}
@Override
public boolean canWrite() {
return false;
}
};
propertiesSet.put(normalProperty);
normalProperty = new PropertySupport.ReadOnly<java.lang.String>(key.getZip(), java.lang.String.class, "ZIP", "The ZIP of " + key.getCity()) {
public java.lang.String getValue() {
return key.getZip();
}
@Override
public boolean canWrite() {
return false;
}
};
propertiesSet.put(normalProperty);
expertProperty = new PropertySupport.ReadOnly<java.lang.String>(key.getState(), java.lang.String.class, "State", "The state of " + key.getState()) {
public java.lang.String getValue() {
return key.getState();
}
@Override
public boolean canWrite() {
return false;
}
};
propertiesSet.put(normalProperty);
expertSet.put(expertProperty);
sheet.put(propertiesSet);
sheet.put(expertSet);
return sheet;
}Снова запустите приложение. Откройте окно «Свойства» (или щелкните правой кнопкой мыши узел и выберите «Свойства», то есть пункт меню, который по умолчанию имеют все узлы), и вы увидите свойства, определенные выше, которые отображаются в окне «Свойства». Если хотите, переместите окно «Свойства» в другое место в приложении, как показано на снимке экрана в начале этой статьи. Обратите внимание, что пользовательская позиция восстанавливается при перезапуске, а не по умолчанию.
- Набор иконок. Теперь добавьте значок в ваш пакет, а затем определите строку, например, в классе Node:
private static final String IMAGE_NODE_BASE = "org/viewer/ui/iconNode.png";
Затем добавьте значок в конструктор CustomerNode, как показано в конце конструктора ниже:
private class PropNode extends AbstractNode {
private Customer key;
private PropNode(Customer key) {
super(Children.LEAF, Lookups.singleton(key));
this.key = key;
setDisplayName(key.getName());
setIconBaseWithExtension(IMAGE_NODE_BASE);
}
...
...
...Далее, может быть, вы хотите, чтобы корневой узел тоже имел свою иконку? Нет ничего проще. Вернувшись в конструктор TopComponent, измените эту строку:
em.setRootContext(new AbstractNode(Children.create(new CustomerNode(list), true)));
… к этой строке:
em.setRootContext(new RootNode(Children.create(new CustomerNode(list), true)));
Обратите внимание, что вместо «AbstractNode», который является одним из вспомогательных классов, которые являются частью Nodes API, у вас теперь есть свой собственный класс Node. Это может быть довольно просто, например, следующим образом:
class RootNode extends AbstractNode {
private static final String IMAGE_MAIN_BASE = "org/viewer/ui/iconMain.png";
public RootNode(Children kids) {
super(kids);
setIconBaseWithExtension(IMAGE_MAIN_BASE);
}
}
Вот и все. Теперь у вас уже есть гораздо более мощное приложение, чем раньше. Больше не хилый маленький JTable: вместо этого у вас есть целый ряд представлений, которые все автоматически синхронизируются друг с другом. Кроме того, теперь вы следуете идиомам Платформы NetBeans, чтобы вы могли постепенно начать использовать их все больше и больше, в то время как ваше приложение все глубже и глубже проникает в Платформу NetBeans.
Наконец, оглядываясь на код выше … это было не так уж много работы, не так ли? В следующий раз мы добавим 5-й модуль для отображения и редактирования выбранного клиента. В этой части, без особой работы, мы получим приложение, которое выглядит так:
И окно редактора, которое вы видите выше, будет в другом модуле, где находится древовидная иерархия. Почему и как все это и многое другое будет обсуждаться в следующий раз.