键盘上的舞者

像写情书一样Coding...

用户操作
[即时聊天] [发私信] [加为好友]
陈维ID:chenweionline
67429次访问,排名1527(-1)好友11人,关注者0
专注 Java Desktop 技术,多年 Java GUI 开发经验。
chenweionline的文章
原创 55 篇
翻译 0 篇
转载 19 篇
评论 142 篇
键盘上的舞者的公告

专注 JAVA Desktop 技术

简单做到极致

最近评论
hupy2007:讲的很好,但是上面提到的新建action的时候,可以选择有条件的可用,上文中写到下面会讲,但是下面也没有提到。我想问一下,project 、edit、open、save等都是些具体什么时候才会可用啊,谢谢了
zhangping:你好,我想我大约是遇上了和你同样的问题。

我的问题是:

我这里有一些java源文件,其中有些注释是日文写的。
在日文操作系统中,运行没有问题,但是在中文操作系统中

用NetBeans6.1重新建立工程,进行Build的时候,会报错和警告:



* <p>&……
兴趣:THS,能否介绍一些资料。
兴趣:如果采用JAVA, 它这方面的功能足够了吗?
兴趣:如果采用JAVA, 它这方面的功能足够了吗?
文章分类
收藏
    相册
    ChinaJoy 2008
    女魔头
    上海浦东软件园
    养在深闺人未识
    Favorite
    Apple-NaNa
    CnGadGet
    NOTCOT.ORG
    虚拟无忌
    技术
    Geertjan's Weblog
    java.net forums
    Let's Swing Java
    Mac Java Community
    NetBeans Rich Client Application (RCP)
    NetBeans星球
    open open
    朋友
    Christina
    企鹅博士
    地平线上
    阿憨月经
    非上上智
    资源
    balloontip
    bluemarine
    JAI
    JAI-ImageIO
    JMONKEYENGINE
    jna
    jrawio
    metadata extraction in java
    pdf-renderer
    QuickTime for Java
    swinglabs
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    转载 Netbeans 插件模块(Plugin Module)的开发收藏

    新一篇: 十年 | 旧一篇: 图书推荐《Rich Client Programming: Plugging into the NetBeans Platform》

    By carol.zhang@sun.com, 3/6/07  

    Netbeans在近年的发展,可说是长足的进步。它不仅是功能强大的集成开发环境,更可以看作是一个开发框架和平台,基于这个平台,通过模块开发,扩展这个平台的功能,或者根据自己的需求,定 制个性化的IDE环境。

    概述

    Netbeans IDE由一个核心运行时环境(core runtime)和一组模块组成。这个core runtime为大多数桌面应用提供公共组件和服务,而“模块”,则是运行在这个core runtime之上的java class,譬如,对于Java语言的支持,就是一个"plugin module",所有Netbeans IDE的跟开发相关的功能都是以“模块”的方式提供的。

    开发者可以根据Netbeans平台所开放的编程接口,开发自己的"plugin module"来实现特定的功能。一般来说,有这么两个目的:

    • 扩展Netbeans IDE。我们可以轻松的加入需要的特性,扩展IDE的功能。譬如,在工具栏上加入Google的搜索框;支持新的文件类型;在Netbeans IDE上支持新的web应用框架的开发;或者实现web 程序在特殊的应用服务器上的部署或调试,等等。
    • 在Netbeans核心平台之上,构造自己的rich client应用。譬如,构造一个有丰富的GUI界面的报表生成器。

    从程序的角度看,一个module就是一个java的archive(.jar)文件,它包含多个java类,以及一个manifest文件,用来标志该jar文件是一个Plugin Module。当 平台的main class运行时,找到所有可用的module,建立一个内存登记表,并且运行这些module指定的在平台启动时的代码,module的其它代码则根据需要装载。

    从发布的角度看,一个module是一个.nbm文件,使用者可以从利用Netbeans IDE中的“update center”功能,从网站下载.nbm文件并安装,或 者选择本地的.nbm文件进行安装。
     

    创建Plugin Module的一般步骤

    Netbeans从5.0版本开始,提供了向导(Wizard)和模板template,来帮助Netbeans module的开发。一般的开发过程是在基于Wizard生成的Template之上,添 加功能。下面以一个简单的Plugin Module开发过程(参考:http://platform.netbeans.org/tutorials/nbm-google.html)为例,来 介绍这个过程:

    1. 创建Plugin Module Project

    Step1

    在创建project的界面上,如图所示,有三类:

    • Module Project:为一个standalone plugin module创建模板
    • Module Suite Project:为一组互相关联的plugin module和library wrapper module创建模板。它们将一起部署。
    • Library Wrapper Module Project:为一个外部的jar文件创建一个plugin module,可以包含在module suite project中。

    这里选择Module Project就可。

    Library Wrapper Module有什么用途?它帮助我们在Netbeans Plugin开发中和第三方jar文件建立依赖关系。举例:如果要申明本模块依赖test.jar,

    • 将test.jar包装成Library Wrapper Module,命名为TestModule
    • 在Project property的API versioning页中,设置这个module的版本号,以及public package(public package是指对于module之外的其它类可见的package)
    • 将这两个模块放到同一个Module Suite Project中
    • 在原module中的“add dependency”的界面中,加入它和TestModule的public package的依赖关系。

    当然,如果模块依赖Netbeans本身提供的module,比如Data System API,只需最后一步即可,不用Library Wrapper Module。

    这和我们在普通的java程序开发过程中,申明和.jar之间的依赖关系的方法有所不同,平时,我们只需将.jar文件放到classpath上即可。Netbeans Module申明依赖关系的方式的好处在于保持很好的模块化,将模块之间的依赖关系最小化,清晰化,并且利用netbeans中的public package的功能,隐藏API的实现细节,利 于模块将来的升级和维护。

    在接下来的界面中,给模块命名(MyFirstModule),选择模块所在的目录(d:\test\nbmodule),生成的java的包名(org.myorg.myfirstmodule)。点击“ finish”就完成了模板的建立。

    2. 让我们看看模板中都包含些什么:

     

    • 源文件和单元测试的包。除了包含和大多数其它普通项目一样的源文件,它还包含一个重要文件:

      • 缺省在org.myorg.myfirstmodule的源文件包下,有一个“layer.xml”文件。它以xml的格式定义了系统的可扩展点,如新增加的 Menu,T oolbars,action属性等以及用户自定义的配置信息,这些信息将合并到整个netbeans系统的配置注册表中(以后会谈到,这个系统的配置注册表称为System FileSystem)。浏 览layer.xml文件的内容,会发现它包含了“FileSystem”这样的tag。

       

    • Important Files:这个目录下包含了Plugin Module项目中重要的配置文件,其中比较重要的有:

    • XML Layer:它是上述的layer.xml文件的图形表达方式,可以通过图形界面对layer.xml进行浏览和修改

    • Module Manifest:位于项目根目录下的manifest.mf 文件指明该项目是一个plugin module,并 包含layer.xml和bundle文件的位置

    • Project Metadata:包含项目的元数据,如项目类型,该模块和别的模块依赖关系等等。在Library Wrapper Module Project介绍中 提到的依赖关系即在这里申明。

    3. 在生成的项目上,就可以利用IDE提供的wizard来创建各种文件模板:

    filetemplate

    如图所示,Netbeans为plugin的开发提供了多种模板以供选择。除了常见的Java Package,Java Class和File/Folder等,有些模板是Plugin Module开发专用的,它们提供了扩展系统的一些方式,运用模板能够迅速的搭起框架,或者获得示例的代码:如,Project Template可以以提供的项目结构和源码为基准,建立新的模板,加 入到主菜单的“File”-> “New Project”的可选项目模板中;Wizard可以帮助你建立一系列向导窗口;Window Component可以用来创建以 TopComponent为子类的窗口类,并且可将对应的窗口对象嵌入到IDE的指定位置;等等。值得注意的是,并不是所有的系统扩展和新功能的添加都能够,或者必须通过模板的方式来实现,如,希 望在Editor中添加代码自动完成的功能,则没有可用的模板,开发者应熟悉在layer.xml中可以添加的系统的扩展点,以及对应的code completion API。

    这里,我们以生成一个新的Action为例。目的是要在系统的工具条上加上一个google搜索栏。当在搜索栏中输入文字,回车后,将调用GoogleAction。因此,在模板列表中选择“ Action...”,出现

    NewAction

    我们知道,凡菜单项或者工具条选项,都有两个状态,激活或者禁止。这里界面上有两个选项正是为这两种状态设置。“Always Enabled”,如名称所示,这个Action总是处于可调用的状态,因 而界面上的选项将总是处于激活的状态。而“Conditionally Enabled (use CookieAction)”则是根据当前所选择的界面对象的状态和条件,来决定是否激活Action。关 于界面上看到的DataObject,Node和Cookie等,我们将在后续的内容中介绍。这里简单起见,选择“Always Enabled”,下一步的界面“GUI Registration”:

    GuiReg

    容易推测出,这一步为Action在界面上注册一个调用入口,并且指定它的位置。它可以是一个菜单项,也可以工具条上的按钮,或者对应某个快捷键等。指定Toolbar和Position之后,在 接下来的步骤中指定类名GoogleAction等信息后,就完成了Action模板的建立。

    让我们看看Netbeans自动为我们做了什么:

    • GoogleAction.java:新生成的CallableSystemAction的子类。注意,在代码中,i mport了org.openide.util等package。这意味着本 module依赖了其它的module。
    • Layer.xml:被修改。因为增加了新的action以及工具条选项。在之前提到的“FileSystem”下,新增加了一些“folder”和“file”。 这些“ folder”和“file”正描述了这个action以及界面注册的情况等等。
    • Project metadata:被修改。因为增加了新的module dependency。

    4. 基于自动生成的模板,运用Netbeans API编写代码,实现所需功能。

    本例将创建JPanel 表单,并和GoogleAction关联。在项目名字上右键弹出的菜单中,选择“new”-> “JPanel Form”,在生成的Panel界面上,建立表单,编 写代码实现Google Search。最后重载GoogleAction类的getToolbarPresenter()方法,将JPanel实例作为返回值,即可。具体的步骤请参见 http://platform.netbeans.org/tutorials/nbm-google.html

    5. 测试和安装

    这两步也非常简单。选择右键菜单中的“Install/Reload in Target Platform”,即可以测试。选择“Create NBM”,可以创建可发布的nbm文件, 用户则可以用菜单中的“Tools”->“Update Center”来安装。如果想卸载,则可用“Tools”-> “Module Manager”功能。

    这是非常简单的例子,但是在这个例中,我们介绍了plugin module的几种类型,创建和发布plugin module的一般步骤,module的基本组成,如何解决 netbeans module dependency,怎么扩展系统的菜单,以及action API的基本用法。但是,在这个示例的介绍中,也留下了很多疑问,比如什么是 System FileSystem,D ataObject,Node等等。在下文中,将比较深入的介绍基于netbeans平台,进行Plugin Module开发所涉及到的基本概念,以及其中API的使用。

     

    基本概念 & API

    我们知道,构建一个框架或者平台软件,必须考虑平台的通用性以及模块和平台之间的接口。当我们学习怎么基于netbeans的平台,做模块开发的时候,不仅 是单纯的开发过程,也 是一个了解netbeans的设计思想的过程。

    文件系统 (FileSystem)

    在netbeans 3.x的版本的IDE中,开发者经常要mount“filesystem”到一个虚拟的名字空间中,每个文件系统都有一个根(“root”),所 有在这个根下的文件都存于这个名字空间中。在netbeans 4.0以后,对于普通IDE使用者而言,在界面上,文件系统的概念已经不存在了,但是类似的概念仍然存在于IDE的基础架构中,开发plugin module仍需涉及。

    Netbeans中,文件系统(FileSystem)扮演着双重角色:它既可以代表磁盘上的物理文件系统,也可以代表IDE和module的配置数据构成的虚拟的文件系统。基于IDE 的配置数据的文件系统称为“System FileSystem”。在当前的FileSystem API中,可以从一个称为Repository的singleton对象里,用 Repository.getDefault().getDefaultFileSystem()方法获得“System FileSystem”,开发者利用System FileSystem,存 取系统的配置数据,以及特定配置目录下的磁盘文件。其它常见的文件系统有JarFileSystem和LocalFileSystem等。LocalFileSystem代表本地磁盘的文件系统。无论是物理的,还 是虚拟的文件系统,它们都共享FileSystem的抽象特性,以及基于其上的FileObject,DataObject,Node等概念。

    从文件系统中,获得的是FileObject对象,它提供关于文件对象的基础信息(名字,父对象,是否存在等),和在对象上的操作(移动,删除等)。FileObject和 java.io.File的主要不同之一在于FileObject提供了change listener的机制。另外,FileObject并不一定是代表磁盘上的物理文件,这种情况在接下来介绍中,可 以看到实例。

    物理的文件系统(如LocalFileSystem)是比较好理解的,可以参考相关API。这里,我们更需要关注关于System FileSystem的几个基本问题:
    1. Netbeans plugin的配置数据是如何表示的?
    2. 配置数据与System FileSystem的关系?
    3. System FileSystem的根(“root”)在哪里?
    4. System FileSystem的扩展点
    5. 如何取得System FileSystem根下的物理文件?
    6. 如何取得System FileSystem里的虚拟文件对象?

    上文提到,每个module都是通过一个“layer.xml”文件来保存配置数据,文件中包含一些虚拟的“文件”和“目录”。这些layer.xml合并在一起就构成了System FileSystem。module就是通过这种方式把配置数据加载到系统中。在module的jar文件中的manifest中,指明了这个layer.xml所处的位置,例如:

    OpenIDE-Module-Layer: org/myorg/myfirstmodule/layer.xml

    根据这个信息,可以在classes目录中找到这个文件。

    一个简单的layer.xml文件就像:
    <folder name="Actions">   
      <folder name="Edit">       
        <file name="org-myorg-myfirstmodule-GoogleAction.instance"/>   
      </folder>
    </folder>

    <folder name="Toolbars">
      <folder name="Edit">
        <attr name="org-openide-actions-FindAction.instance/org-myorg-myfirstmodule-GoogleAction.shadow" boolvalue="true"/>
        <file name="org-myorg-myfirstmodule-GoogleAction.shadow">
          <attr name="originalFile" stringvalue="Actions/Build/org-myorg-myfirstmodule-GoogleAction.instance"/>
        </file>
      </folder>
    </folder>

    <folder name="myFolder"> 
      <file name="vFile">
         <attr name="attr1" stringvalue="attrValue"/>   
      </file>   
      <file name="myFile.txt" url="resource/realfile"/>
    </folder>

    其中有一些“folder”是系统预先定义好的,比如,例中的“Actions”和“Toolbars”,当module往IDE的toolbar上添加新的选项的时候,在 “Toolbars”以 及它的子目录下,必然出现对应与这个新选项的“file”条目和相关的属性。可以看到,这些预定义的folder正是这个系统的扩展点。

    还有一些folder是用户自定义的,比如例中的“myFolder”,注册于System FileSystem中,可以动态保存用户自己的配置或者资源信息。这些信息可以以虚拟文件的形式,存 于layer.xml中:

    FileObject vFile = Repository.getDefault().getDefaultFileSystem().findResource("myFolder/vFile");
    System.out.println("the attr is:" + vFile.getAttribute("attr1"));

    程序将打印出"the attr is attrValue"。这是一个在System FileSystem中代表虚拟文件的FileObject的例子。当然,如果需要一个物理文件作为实体,也可以用“ url”属性建立虚拟文件和物理文件之间的映射。如例中的 <file name="myFile.txt" url="resource/realfile"/>。 用下面的代码,程 序将获得相对于layer.xml路径的"resource/realfile"物理文件,并且构造出File Object:

    FileObject res = Repository.getDefault().getDefaultFileSystem().findResource("myFolder/myFile.txt");

    另外,在运行过程中,还可以在System FileSystem的根下,往myFolder目录下添加新的物理目录和文件:

    FileObject myFolder = Repository.getDefault().getDefaultFileSystem().getRoot().getFileObject("myFolder"); myFolder.createData("newFile");

    程序将获得System FileSystem根下myFolder目录对应的FileObject,并调用createData方法,在这个目录下创建一个“newFile"文件。在 module的开发调试环境中这个“根“位于<myModulePath>\build\testuserdir\config,在以nbm的格式安装下,位 于<userdir>\.netbeans\5.5\config目录下(在windows环境中,<userdir>常见于“C:\Documents and Settings\<useraccount>”)。

    更cool的是,在System FileSystem中,可以使FileObject成为java对象的工厂。在上例中以.instance为后缀的文件,就是这样的例子。我们在介绍Data System API的时候会详细介绍。

    可见,在netbeans中,文件系统以及文件对象扮演了多种角色,但是它们基于同一抽象的特性,使下面介绍的DataObject,Node等能广泛适用。

    数据系统 (Data System)

    DataObject是FileObject的wrapper。FileObject代表的是一个类似于文件的实体,而DataObject代表的则是文件内容的模型。文件类型是通过后缀名来标志的,一 般来说不同的文件类型对应于不同的DataObject的实现。DataLoader是创建DataObject的工厂类,如果程序需要支持新的文件类型,则应实现相应的DataLoader 和DataObject,并在module的manifest中注册,如:

    Name: org/netbeans/modules/povray/PovDataLoader.class
    OpenIDE-Module-Class: Loader

    如果不需要支持新的文件类型,则不用和DataLoader打交道。只须用下面的方法获得某个fileobject的DataObject:

    DataObject.find(someFileObject);

    和DataObject交互的方式是通过getCookie()和getLookup()方法。这两个方法应该是可以互换的。getCookie()在将来的netbeans版本中,将 被getLookup所替代。注意,这里的Cookie和http协议中的Cookie没有关系。它代表的是这个DataObject能够提供的操作或者服务。用法如下:

    OpenCookie open = someDataObject.getCookie (OpenCookie.class);



    if (open != null) {

    open.open();

    }

    如果在someDataObject上如果支持open操作,则从这个DataObject中获得实现了OpenCookie接口的对象,然后调用这个对象上的open操作。这样,DataObject 中并不实现具体的操作,接口实现代码封装在cookie中,通过getCookie和getLookup(关于Lookup,在后面介绍)的编程接口,提供给调用者。

    前面提到,System FileSystem中,以.instance为后缀的文件构造的FileObject,能成为java对象的工厂。让我们看看是怎么实现的:在例中的lay.xml中,

    //fo中包含了要构造的对象的类名。
    FileObject fo = Repository.getDefault().getDefaultFileSystem().findResource("Actions/Edit/org-myorg-myfirstmodule-GoogleAction.instance")

    DataObject dobject = DataObject.find(fo); //根据后缀名,获得DataObject对象。
    InstanceCookie ic = dobject.getCookie(InstanceCookie.class) //从DataObject中,获 得InstanceCookie的实现
    if (ic != null) { //如果该DataObject支持创建新的实例的操作
      GoogleAction myAction = (GoogleAction)ic.createInstance(); //利用Cookie接口,创建Java对象
    }

    和以.instance为后缀名的情况类似,如果文件对象的后缀名是.ser,即对象的串行化的结果文件,也可以通过获得InstanceCookie的方法来创建被串行化的对象。

    节点(Nodes)

    前面提到,FileObject是文件的抽象,DataObject是文件内容的模型,而Node是表现层的对象。它们有actions(操作),properties(属性),本 地化的显示名称以及图标等等,封装了对象在人机接口方面的特性。需要注意的是,Netbeans 的Node不是GUI对象,和JDK中的TreeNode没有继承关系。但类似的是,它一般来说,也 是一个树型结构,每一个Node有Children对象,提供子节点的列表。

    • Node和Lookup
      和DataObject类似,每个Node对象都有一个Lookup对象,来存储上下文相关的信息。对于两者而言,调用者都可以通过getLookup方法获得 其上下文以及支持的操作。同 样Node也有getCookie方法,但是它的典型实现是,代理给了DataObject的getCookie()方法。

      Node实例中的Lookup对象是如何设置的呢?这里列举几种方法:
      - 在API中,有可能用到Node的基本实现类AbstractNode(注意,它其实并不是一个抽象类), 在AbstractNode的构造方法中,可以以Lookup为参数。
      - 从DataObject中调用用getNodeDelegate()方法获得的Node对象,可能已经包含了Lookup。
      - 子类如从FilterNode继承,则子类的Lookup可以从代理Node对象中获得。
      - 子类中重载Node的getLookup方法,返回所需的Lookup对象

      至于Lookup的详细说明,以及怎么创建一个Lookup对象,见下章节。
    • Node和Explorer Views
      Explorer Views是界面对象,Node可以用不同的View展现出来。这些View对象包含在Explorer & Property Sheet API中,比 如BeanTreeView用来显示Node 的树型结构,ListView用来显示Node的列表等。至于怎样用View去展现Node,会在Explorer API中介绍。
    • Node和DataObject
      DataObject可以用Node,也可以不用Node来表现。同样,Node后面的数据,可以是DataObject,也可以不是DataObject。但是,在某些场景下是互相关联的,它们 之间也有API可以方便的互相转换。比如,希望用界面树型组件来显示磁盘上的某个目录结构,或者System FileSystem中的虚拟目录。很自然,从FileSystem,到 FileObject,D ataObject,Node,最后用Explorer View显示出来。

      现在我们从编程的角度,看看FileSystem,FileObject, DataObject, Node之间调用和转换关系:

      //Find a file on disk
      FileObject f = Repository.getDefault().getDefaultFilesystem().getRoot().getFileObject("lsome/folder/someFile.txt");

      //or if something passes you a File...
      FileObject f = FileUtil.toFileObject (new File("some/folder/someFile.txt"));


      //Turn a FileObject into a File (may fail for virtual filesystems)
      File f = FileUtil.toFile (someFileObject)

      //Get the DataObject for a FileObject
      DataObject obj = DataObject.find (someFileObject)

      //Get the FileObject a DataObject represents
      FileObject file = someDataObject.getPrimaryFile();

      //Get the Node that represents a FileObject
      Node n = someDataObject.getNodeDelegate();

      //Get the DataObject a Node represents (if any)
      DataObject obj = (DataObject) someNode.getLookup().lookup(DataObject.class);
    • Node和Action
      Node可以提供一组Actions,这些Actions表示在该node被选中的时候,右键弹出菜单中将显示的项目。在这组Actions中,开 发者可以加入一个AbstractAction的子类, 也可以从SystemAction中获得系统菜单中支持的如“delete”,“copy”,“save”等Action。如下例所示:

      public Action[] getActions(boolean popup) {
          DataFolder df = (DataFolder)getLookup().lookup(DataFolder.class);
          return new Action[] {
              new AddRssAction(df),
              SystemAction.get(DeleteAction.class),
              SystemAction.get(SaveAction.class)
          };

      当该Node被选中,在点击右键弹出的菜单中,会有三个选项,一个是“add”操作,操作的实现在AddRssAction中,该操作是在激活状态,因为AddRssAction就是这 个action的实现;第二个是系统Action中的“delete”操作。操作如“delete”,“copy”,“paste”,“cut”,它们的实现可以由ExploreUtil的工厂方法来 提供,它 们的激活与否是由ExploreManager以及当前的剪贴板等状态来控制的。第三个选项是系统Action中的“save”操作,它的激活与否在于该Node的Lookup或者 cookie中有没有SaveCookie的实现。简而言之,getActions()返回了右键菜单中的选项,但是这些选项是否激活,取决于运行系统是否能以各种方式获得对应action的 实现。< /p>

    Lookup

    在DataObject和Node的介绍中,多次提到Lookup。Lookup( http://www.netbeans.org/download/dev/javadoc/org-openide-util/org/openide/util/Lookup.html)类,是 被广泛应用于netbeans API中一个很重要的概念,我们也可以把它看成是Netbeans版本的IoC的实现,它也是各个模块之间实现decouple的关键所在。可以先简单的把它理解为,它 是一个Map,其中keys是class对象,对应每个key的value,是这个class的实例。一般来说,这个class对象是一个interface,定义了某服务的接口,而class实例,是 这个服务的实现。

    在Netbeans中,有两种Lookup的用法。一种是用于从全局的服务登记表中获得某个服务的实现,Lookup.getDefault()调用返回的Lookup对象,即这个全局的服务登记表;另 一种,局部的用法,用来查询某个对象是否支持某个服务,并且获得它所支持的服务的实现。很多类型的对象都有自己的Lookup,比如TopComponent,DataObject,Node等等,可 以用类似于obj.getLookup()调用来获得obj的Lookup,这个Lookup对象里存的是当前上下文信息。对于调用者来说,只需获得它所关心的对象的Lookup,从中检索并调用相应的服务。& amp; amp; amp; lt; /p>

    这里我们主要探讨一下Lookup的局部用法。用户在IDE环境中的常用操作之一是,移动焦点,并且“选择”某个对象,在这个对象上执行相应操作。当前焦点所在的对象,也称当前选中的对象,活动的对象,或 者处于激活状态的对象。Netbeans IDE菜单中的常见功能,比如“打开”,是在当前所选中的对象上执行“打开”操作。显然对于不同的对象,“打开”操作的实现是不一样的。当选择不同的对象的时候,也 可见属性窗口中的属性值随着对象的不同而变化。那么在同样一个框架下,如何判断某个特定对象是否支持“打开”这样的公用操作,并且执行操作?当焦点对象变化的时候,框架如何得到通知,从而作相应的变化?在 Netbeans中,Lookup就是解决类似问题的答案。

    例如下面这个例子就是从Node对象中获得它的Lookup:

    Node[] n = TopComponent.getRegistry().getActivatedNodes();



    if (n.length == 1) {

    OpenCookie oc = (OpenCookie) n[0].getLookup().lookup(OpenCookie.class);

    if (oc != null) {

    oc.open();

    }

    }

    这段代码,就可以用于实现上文描述的关于“打开”操作的场景,Lookup的应用,使得“打开”这个操作不需关心当前活动的节点的内容,也不用关心该节点将怎么执行 “打开”操作,只 要这个节点的Lookup中能够检索到OpenCookie接口的实现,调用其open函数即可。这样就实现了模块之间的解耦。关于Lookup的更细节的用法说明,请参见:

    Lookup的基本概念:
    http://openide.netbeans.org/lookup/

    用Lookup SPI构造自己的Lookup:
    http://www.netbeans.org/download/dev/javadoc/org-openide-util/org/openide/util/lookup/doc-files/lookup-spi.html

    Lookup API的使用:
    http://www.netbeans.org/download/dev/javadoc/org-openide-util/org/openide/util/lookup/doc-files/lookup-api.html
     

    Window System

    在Window System API中,最常用到的是TopComponent类,它是可嵌入式的窗口组件的父类,负责跟Netbeans的窗口系统交互。在 前面介绍Netbeans提供的代码模板类型中,就提到TopComponent。选择“Window Component”模板自动生成的java类,就是TopComponent的子类。Top component可以是一个单独的窗口,也可以嵌入在tab页中。Netbeans的整个界面环境被划分为不同的部分,每个部分都有名称。比如:“explorer”,一般指位于界面左上角位置的窗口部分,“ Project”,“Files”,“Runtime”这些都是位于“explorer”位置的窗口组件。"Editor",指的是位于界面中间的部分,比如各种编辑器都是位于这个部分。生成新的窗口组件时,会 要求指定窗口所处的位置。

    每一个TopComponent实例都有一个Lookup的对象来标志其上下文,有一组Explorer view对象作为其界面元素,和一个或者多个激活的节点(Nodes)。程序中,一 般用associateLookup方法来设置TopComponent的Lookup对象,而当前激活的nodes则一般从下文将要介绍的ExplorerManager中得到。

    Explorer & Explorer Views

    Nodes提供了一组层次化的对象,而Explorer API则提供了界面对象(Explorer View)来显示这些Nodes。但是Nodes和界面对象view之间,并没有直接的调用关系,它 们之间的交互是通过ExplorerManager来实现的。用MVC的观点看,ExplorerManager就是Controller,它提供一个或者多个view要显示的node内容,管 理了views之间的共享的状态,如当前选中的节点和它的Lookup。当用户在某个view上的操作导致共享状态的改变时,该view对象会调用ExplorerManager的方法更新共享状态,E xplorerManager再将共享状态的改变通知到其它的view。结合这些概念,来看一段代码:

    class FeedTopComponent extends TopComponent implements ExplorerManager.Provider {

    private final ExplorerManager manager = new ExplorerManager();

    private final BeanTreeView view = new BeanTreeView();

    private FeedTopComponent() {

    add(view, BorderLayout.CENTER);

    view.setRootVisible(true);

    try {

    manager.setRootContext(new RssNode.RootRssNode());

    } catch (DataObjectNotFoundException ex) {

    ErrorManager.getDefault().notify(ex);

    }

    ActionMap map = getActionMap();

    map.put("delete", ExplorerUtils.actionDelete(manager, true));

    associateLookup(ExplorerUtils.createLookup(manager, map));

    }



    public ExplorerManager getExplorerManager() {

    return manager;

    }

    ...........

    }


    示例中,FeedTopComponent即上文提到的TopComponent的子类,BeanTreeView作为一个Explorer View对象加入到了窗口对象中。B eanTreeView需要显示的节点,以及共享状态是由ExplorerManager来控制的。通过调用ExploreManager的setRootContext方法,设置了这组节点的根。

    因为ExplorerManager管理了nodes的状态,所以前面提到能从TopComponent窗口实例中获得一组当前激活的节点,实际上,是从其内置的ExplorerManager 中获得。T opComponent的Lookup对象用ExplorerUtils.createLookup(ExplorerManager,ActionMap)方法创建,使 得TopComponent的Lookup实际上,代理给了由ExplorerManager管理下的当前活动节点的Lookup和ActionMap中支持的action操作。

    ActionMap对象维护了action的名字和对应的action实现的映射。示例中,ActionMap添加了“delete”操作,通 过把ActionMap和ExplorerManager一起加入到TopComponent的lookup中,使“delete”操作能够在ExplorerManager管理下的nodes上执行。也 就是说当某个node选中的时候,系统的“delete”菜单会被激活。

    其它的API

    Netbeans中还有很多别的API,可以参见Netbeans的网站上javadoc和相关资料。当然关于API的了解,往往也是在实际运用中得到增强的。

    总结

    本文首先介绍了创建Netbeans Plugin Module的一般步骤,然后就开发过程中要涉及到的基本概念做了探讨,目的在于了解Netbeans Plugin Module开发中的基本思想和要素,为更深入的学习和理解打下一定的基础。

    参考文档

    http://platform.netbeans.org/tutorials/index.html

    http://www.netbeans.org/download/dev/javadoc/

     

    发表于 @ 2007年06月08日 13:13:00|评论(loading...)|收藏

    新一篇: 十年 | 旧一篇: 图书推荐《Rich Client Programming: Plugging into the NetBeans Platform》

    评论

    #学习NB插件开发 发表于2008-05-07 11:17:22  IP: 218.87.140.*
    您能还有什么其他插件开发的例子不?我刚刚开始学这个东西,很多东西都还不懂。
    #chenweionline 发表于2008-05-07 17:38:44  IP: 61.173.64.*
    http://fox.jenming.info/
    我学习netbeans插件开发时这个网站给我很多帮助
    #hupy2007 发表于2008-10-07 14:43:37  IP: 218.58.59.*
    讲的很好,但是上面提到的新建action的时候,可以选择有条件的可用,上文中写到下面会讲,但是下面也没有提到。我想问一下,project 、edit、open、save等都是些具体什么时候才会可用啊,谢谢了
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © 键盘上的舞者