NetBeans RCP - 使用 Node & ExplorerManager 结合 BeanTreeView 编写一个磁盘文件树

版权声明:转载时请务必保留以下作者信息和链接
作者:陈维([email protected])作者的网站:http://www.chenwei.mobi

在 NetBeans Platform (以后简称 NP)里,Node 负责提供内容在界面组件里的表现,Tree 、 List 、Palette、Property Sheet 等界面组件都和 Node 有关,所以 Node 结构的设计对于内容在界面上表现十分重要。这篇文章我试图通过构建一个类似 Windows 资源管理器上的磁盘文件树的模块样例程序,来说明如何使用 Node API 结合 NP 界面组件创建桌面应用。

我假设读者已经了解如何建立一个 NetBeans 模块,直接进入正题。

NP提供了一系列可重用的组件供开发者使用,BeanTreeView就是其中之一。事实上,无论是使用 BeanTreeView还是 Swing 中的 JTree 编写一个磁盘文件树,首先要确定节点(目录)和子节点(子目录)的查询结构。下面我们首先创建磁盘文件树对应的 Node 体系结构。

1、设计 Node

根据我们的需求(磁盘文件树),我们需要设计一个 Node 用来表现驱动器、文件夹、文件以及特殊文件夹(例如“桌面”),整个文件系统会构建许多 Node。通过这些分析,在项目引用的库中导入 Node API 后(导入过程略)建立一个类 FileNode。

package mobi.chenwei.nbm.explorer;

import java.awt.Image;
import java.io.File;
import java.io.FileFilter;
import javax.swing.ImageIcon;
import javax.swing.filechooser.FileSystemView;
import org.openide.nodes.AbstractNode;

/***/ /**
*文件节点。用于表现驱动器、文件夹、文件以及特殊文件夹...
*
*
@authorChenWei
*@websitewww.chenwei.mobi
*@[email protected]
*/

public class FileNode extends AbstractNode implements Comparable ... {

privatestaticFileSystemViewfileSystemView=FileSystemView.getFileSystemView();
privateFilefile;

publicFileNode(Filefile,FileFilterfilter)...{
super(newFileChildren(file,filter));
this.file=file;
}


publicintcompareTo(Objecto)...{
if(oinstanceofFileNode)...{
Filef1
=getFile();
Filef2
=((FileNode)o).getFile();
returnf1.compareTo(f2);
}

return0;
}


publicFilegetFile()...{
returnfile;
}


publicstaticFileNodecreateHomeNode(FileFilterfilter)...{
Filefile
=fileSystemView.getHomeDirectory();
returnnewFileNode(file,filter);
}


@Override
publicStringgetHtmlDisplayName()...{
returnfileSystemView.getSystemDisplayName(getFile());
}


@Override
publicImagegetIcon(inttype)...{
//这里将Icon强制转换为ImageIcon在MacOSX平台上会抛出异常!
return((ImageIcon)fileSystemView.getSystemIcon(getFile())).getImage();
}


@Override
publicImagegetOpenedIcon(inttype)...{
//这里将Icon强制转换为ImageIcon在MacOSX平台上会抛出异常!
return((ImageIcon)fileSystemView.getSystemIcon(getFile())).getImage();
}

}

在 FileNode 里我们继承了 AbstractNode,它实现了抽象类 Node 的一些基本方法。同时,我们实现的 Comparable接口,它用来对于节点进行排序,之后我们还会提到。FileNode 里包含了它表示的 File 以及当前文件系统的 FileSystemView对象。通过覆写 getHtmlDisplayName(),getIcon() 和 getOpenedIcon() 来提供 Node 在界面上的具体表现(这里我需要说一些与 Node 无关的话,在 getIcon() 和 getOpenedIcon() 里我去的当前系统文件浏览器中显示的文件、目录或文件夹的图标然后强行转换成 ImageIcon,这里的强制转换在 Mac OS X 系统中会抛出异常,因为它并不是 ImageIcon 而是 ,我目前还不知道怎么取得Mac 文件系统中的文件图标)。另外,创建了一个静态方法 createHomeNode() 用来取得文件系统的根,可以看到其中包含一个文件过滤器,你可以定制这个文件过滤器来取得你需要的文件,在后面的代码中我实现了一个简单的文件夹过滤器。

大家可以看到 FileNode 的构造函数里有一个 FileChildren 的实例,我们通过它来完成完整的目录结构。好了,现在我们要为 FileNode 建立它的 Children。

package mobi.chenwei.nbm.explorer;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Collection;
import org.openide.nodes.Children;
import org.openide.nodes.Node;

/***/ /**
*FileNode的Children。
*
*
@authorChenWei
*@websitewww.chenwei.mobi
*@[email protected]
*/

public class FileChildren extends Children.SortedArray ... {

privateFileparent;
privateFileFilterfilter;

publicFileChildren(Fileparent,FileFilterfilter)...{
this.parent=parent;
this.filter=filter;
}


@Override
protectedCollection<Node>initCollection()...{
File[]children
=parent.listFiles();
ArrayList
<Node>fileNodes=newArrayList<Node>();
for(Filef:children)...{
if(filter==null||filter.accept(f))...{
fileNodes.add(
newFileNode(f,filter));
}

}

returnfileNodes;
}

}

实现 Children 一般都直接继承 Children.Array,Children.Map,Children.Keys,Children.SortedArray,Index.ArrayChildren 或 Children.SortedMap。FileChildren 继承了 Children.SortedArray,它可以管理 Node 排序,现在我们回过头看看实现了 Comparable接口的 FileNode,在 compareTo() 里定义了排序规则(通过比较两个 File 来)。当 Children 第一次被使用时,initCollection() 被调用,把文件夹中过滤出的子文件重新包装成 FileNode 并且将集合提交返回。

2、设计界面组件与 ExplorerManager

当我们设计完 Node 结构之后,我们来看一看界面上的表现。

首先通过向导创建 TopComponent 组件 ExplorerTopComponent(创建过程略),它是 NP 上的 Dockable Window。在项目引用的库中导入 Explorer & Property Sheet API 后(导入过程略)后我们在 ExplorerTopComponent 里创建 BeanTreeView 和 ExporerManager 的实例并且实现 ExporerManager.Provider接口,在 getExplorerManager() 中返回 ExporerManager 的实例。

final class ExplorerTopComponent extends TopComponent implements ExplorerManager.Provider ... {

privateBeanTreeViewfileTree;
privateExplorerManagerexplorerMgr;

privateExplorerTopComponent()...{

//........

myInit();
}

//........

privatevoidmyInit()...{
fileTree
=newBeanTreeView();
explorerMgr
=newExplorerManager();
add(fileTree,BorderLayout.CENTER);
this.associateLookup(ExplorerUtils.createLookup(explorerMgr,getActionMap()));
explorerMgr.setRootContext(FileNode.createHomeNode(
newDirFilter()));
//explorerMgr.setRootContext(FileNode.createHomeNode(null));
}


publicExplorerManagergetExplorerManager()...{
returnexplorerMgr;
}

}

从上面的代码,我们看到 myInit() 里具体实例化了 BeanTreeView 和 ExploterManager,将 BeanTreeView 加入面板中央区域,然后通过 associateLookup() 和 ExplorerUtils.createLookup() 建立了一个属于 explorerMgr 的Lookup。再通过 FileNode.createHomeNode() 创建了它的根。构造根 Node 时传入了一个文件夹过滤器,从而使 BeanTreeView 中只显示非隐藏的文件夹。

package mobi.chenwei.nbm.explorer;

import java.io.File;
import java.io.FileFilter;
import java.io.Serializable;

/***/ /**
*文件操作中的文件夹过滤器类。
*
*
@authorChenWei
*@websitewww.chenwei.mobi
*@[email protected]
*/

public class DirFilter implements FileFilter,Serializable ... {
//是否过滤隐藏文件夹。
privatebooleanfiltrateHidden=false;

publicbooleanaccept(Filepathname)...{
if(pathname.isDirectory())...{
if(isFiltrateHidden()&&pathname.isHidden())...{
returnfalse;
}
else...{
returntrue;
}

}
else...{
returnfalse;
}

}


publicbooleanisFiltrateHidden()...{
returnfiltrateHidden;
}


publicvoidsetFiltrateHidden(booleanhidden)...{
this.filtrateHidden=hidden;
}

}

现在一个磁盘文件树就完成了,可以在模块项目上点击鼠标右键,选择 "Install/Reload in Target Platform" 项执行观看效果。

NetBeans RCP - 使用 Node & ExplorerManager 结合 BeanTreeView 编写一个磁盘文件树

完整模块源码下载:

http://dl2.csdn.net/down4/20080119/19153226648.zip

你可能感兴趣的:(swing,浏览器,OS,项目管理,Netbeans)