NetBeans选择管理教程II 使用Nodes

本文来源:https://netbeans.apache.org/tutorials/60/nbm-selection-2.html

上一篇NetBeans选择管理教程I讲述了TopComponent对象的Lookup,以及编写其他组件的焦点事件。

本教程着重于Node API,它使您不仅可以进行组件级选择,还可以进行更精细的视图和选择。当然,您可以编写一个组件,该组件可以根据需要读取和写入其自己的Lookup,并以这种方式提供更精细的选择逻辑。但是,Nodes API使其非常容易执行此操作,并且与您自己执行操作相比,具有许多优点。

Node API 介绍

第一个优点是Nodes API提供了一个表示层,即以某种方式编辑的数据模型与向用户公开数据模型的UI组件之间的一层。这是非常有用和强大的,因为可以以多种方式或通过多个UI呈现相同的模型。

第二个优点是Explorer API(该模块org.openide.explorer提供了大量组件,包括树,列表,树表等),这些组件可以呈现Node及其子元素。

Node是通用层次的结构对象,一个Node 具有:

  • Children—子级下的层次结构中的节点,可以显示在树中

  • Actions—可以在右键弹出菜单中显示的一系列操作

  • Display Name—一种人类可读的本地化显示名称,可以在UI组件中显示

  • Icon—可在UI组件中显示的图标

和Node 可以出发上述任何更改,并且Explorer UI组件将自动更新自身。

这并不是说上一个教程内容是无用的,相反,这是Node API可以工作的原因。 原因是org.openide.nodes.Node有一个方法,你猜对了,getLookup()。实际上,当在IDE中更改Projects选项卡中的选项时,例如,Projects标签是一个顶部组件,他代理对树中当前选择的任何对象的查找,就像Utilities.actionsGlobalContext()一样,查找代理任何一个呗聚焦的组件,并在焦点发生变化时触发更改。

由于Explorer API中的组件,创建自己的节点树视图非常容易,并且只需要很少的代码就可以再自己的组件中实现这种类型的代理。查看器类型的组件,比如上个教程中的MyViewer组件,不需要做任何特殊的事情来响应浏览器组件中的选择更改—它们将在选择更改时自动得到通知。

创建一个Explorer View

现在要做的第一件事就是对MyEditor组件实质性的修改。首先在编辑器中打开它。

1、打开MyEditor项目的属性对话框,选择库,点击添加,对话框搜索BeanTreeView,列出的Explorer&Property Sheet API,点击确定。如下所示,这将添加对Explorer API模块的依赖关系,因此您可以使用其中的类。

2、接下来,清空按钮中的代码

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
}

3、切换到设计界面,选择所有组件,删除他们。

4、在Component Inspector(组件查看器),右键TopComponent 节点,设置 Layout > BorderLayout

5、添加一个JScrollPane组件,让它占据整个界面。所有的Explorer UI组件都是子类JScrollPane,因为只需要更改实例化代码即可创建Explorer view。

6、选中JScrollPane右键,选择自定义代码,在代码定制器中添加new BeanTreeView()

BeanTreeView是Explorer API的一个组件,一个基本的JTree。基于Node和子节点的视图,具有内奸的处理弹出式菜单、搜索等功能。

7、切换到代码编辑器,导入BeanTreeView类。

8、下一步是给树上一些东西。Explorer UI组件的工作方式如下:添加到容器后,他们将搜索该容器及其祖先,知道找到实现ExplorerManager.Provider的容器为止。因此,您不会将节点设置为直接在组件上查看。您可以在组件的管理器上设置它。这使得有可能有多个views,master/detail views等,都由一个管理器管理。在MyEditor添加以下内容:

public class MyEditor extends TopComponent implements ExplorerManager.Provider {

然后修复导入,实现所有抽象方法

    private final ExplorerManager mgr = new ExplorerManager();
    @Override
    public ExplorerManager getExplorerManager() {
        return mgr;
    }

9、现在,由于目标是一个可以显示多个APIObject的组件,您需要一个或者两个Node来显示在组件中。每个对象将拥有自己的APIObject实例。所以,现在你只需要添加代码来为树形视图创建一个跟节点。在构造函数添加以下代码:

mgr.setRootContext(new AbstractNode(new MyChildren()));

10、出现AbstractNode和MyChildren的2处错误,AbstractNode去库中搜索添加依赖,然后引入。MyChildren我们会在后面编写它。

实现Node 和Node Children

您会注意到您正在使用AbstractNode上面的类。尽管它的名字,它不是一个抽象类!这是一个使用程序,实现了org.openide.nodes.Node类,可以节省您一些时间和麻烦,您也自己创建一个AbstractNode并向其传递Children将为其提供子节点的对象,而不是自己实现Node,然后设置图标和名称。因此,这是一种获取Node对象的简单方法,而无需对Node本身进行子类化。

下一步是实现MyChildren,以便在初始节点下面有子节点。

1、右键org.myorg.myeditor的package,新建 > java class,命名为MyChildren,点击完成

2、继承Children.Keys,修复导入,实现抽象方法。

class MyChildren extends Children.Keys {

3、首先。您需要重写一个方法addNotify(),与Swing组件中的addNotify()模式一样,addNotify()在第一次关注这个Children对象时被调用,第一次请求它的子节点时。因此,您可以延迟子节点的创建,知道用户在视图中真正展开父节点并需要看到他们。将插入符号放在源文件中的某个位置,右键Insert-code,然后选择覆盖方法,再出现对话框,展开Children,选择addNotify方法,点击完成。

4、编写addNotify方法代码

    @Override
    protected void addNotify() {
        APIObject[] objs = new APIObject[5];
        for (int i = 0; i < objs.length; i++) {
            objs[i] = new APIObject();
        }
        setKeys(objs);
    }

你可以能从Children.Keys的名字中菜刀了,父类所做的是获取一个关键对象的数组或集合,并充当节点的工厂。因此,在addNotify中调用setKeys(),告诉要请求的子节点。对于传递的setKeys()的数组或者集合中的每个元素,在createNodes()将被调用一次。(注意:这意味着如果你愿意,可以有多个节点来表示一个对象)

5、现在,需要实现创建Node对象的代码,然后修复导入。

    @Override
    protected Node[] createNodes(Object o) {
        APIObject obj = (APIObject) o;
        AbstractNode result = new AbstractNode(new MyChildren(), Lookups.singleton(obj));
        result.setDisplayName(obj.toString());
        return new Node[]{result};
    }

6、最后一步是安装一些管道代码,将explorer 管理器连接到TopComponent的Lookup。删除该行

private final InstanceContent content = new InstanceContent();

7、修改MyEditor的构造函数。

    public MyEditor() {
        initComponents();
        associateLookup(ExplorerUtils.createLookup(mgr, getActionMap()));
        mgr.setRootContext(new AbstractNode(new MyChildren()));
        setDisplayName("My Editor");
    }

运行应用

您可能已经注意到,因为创建的每个AbstractNode 穿戴了一个新的MyChildren实例,所以最终得到的事一个无限深的APIObject树,每个节点将有5个子节点,每个节点都有自己的APIObject

如果运行没有变化,右键SelectionSuite,选择clean和build,然后再次run

请注意,当您单击和/或展开不同的节点时,MyViewer会自动更新以显示APIObject属于每个节点的属性值

探索Explorer

现在,您已经拥有了上面的代码,探索Netbeans中可用的其他组件也很有趣,这些组件也可以呈现Node和它的子节点。只需要在表单编辑器中打开MyEditor并更改自定义创建代码属性,以使用不同的组件即可完成此操作。对于其中一些组件,您需要用不同类型的组件替换JScrollPane(需要在表单编辑器中删除JScrollPane,并将代码add (new BeanTreeView(), BorderLayout.CENTER) 添加到构造函数中)。一些选择是:

这里介绍有几个字面意思:

1、以下组件可以再自定义创建代码属性中使用,JScrollPane并非全都支持以下组件,需要其他类型组件替换。

2、也可以删除JScrollPane,在构造函数中创建BeanTreeView

  • ListView —在JList中显示节点(您可以设置它应该进入Node层次结构的深度)

  • TreeTableView(树表),其最左列为树的表

  • ChoiceView-节点及其子节点的组合框视图

  • MenuView -a JButton弹出一个节点及其孩子的菜单

  • IconView-一个组件,它以相等间距的图标显示Node子级,类似于Windows Explorer

ListView和TreeTableView支持JScrollPane,其他3个没试验成功

删掉JScrollPane,add构造函数添加的方式没试验成功

处理多选

您可能已经注意到BeanTreeView,Node的基本树视图可以一次选择多个节点。因此,可能需要修改查看器组件以显示有关所有选定节点的信息:

1、打开org.myorg.myviewer.MyViewerTopComponent编辑器

2、用resultChanged()以下代码替换侦听器方法:

public void resultChanged(LookupEvent lookupEvent) {
    Lookup.Result r = (Lookup.Result) lookupEvent.getSource();
    Collection c = r.allInstances();
    if (!c.isEmpty()) {
        StringBuffer text1 = new StringBuffer();
        StringBuffer text2 = new StringBuffer();
        for (Iterator i = c.iterator(); i.hasNext();) {
            APIObject o = (APIObject) i.next();
            text1.append (o.getIndex());
            text2.append (o.getDate().toString());
            if (i.hasNext()) {
                text1.append (',');
                text2.append (',');
            }
        }
        jLabel1.setText (text1.toString());
        jLabel2.setText (text2.toString());
    } else {
        jLabel1.setText("[no selection]");
        jLabel2.setText ("");
    }
}

你可以看到,不仅由ExplorerUtils创建的Lookup代理节点被选择,它还可以正确的代理查找多个节点

回顾概念

要回顾介绍的一些概念:

  • 一个Lookup就像一个Map,其中键是类,值是这些类的实例。将一个Lookup视为对象,进入流入和流出的地方也很有用,您还可以订阅特定的类型对象去到达和离开通知。
  • Utilities.actionsGlobalContext()是一个Lookup代理,它替代当前具有键盘焦点Lookup的任何一个TopComponent,并在焦点移至其他组件时触发更改。
  • Node表示对象,可以再tree、list 护着其他Explorer API组件中显示,每个Node都有自己的Lookup
  • 就像TopComponents的Utilities.actionsGlobalContext代理一样Lookup,(因此,您可以只请求查找结果并侦听结果中的更改,而不必自己跟踪焦点更改),ExplorerUtils创建的Lookup也是如此。createLookup(ExplorerManager, ActionMap) 将创建一个Lookup,自动代理查找任何Node(s) 被选择在一个Explorer component中。

下一步 

现在已经有了一个视图,他可以显示一些底层模型对象Node,在接下来的教程中,你可以加强节点的Action和性能以及显示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值