Eclipse插件开发之TreeViewer

contentprovider在插件开发和RCP(Rich Client Platform)开发中常常被用到,譬如你要创建一个TreeViewer(树形控件)就需要一个ITreeContentProvider,如果要实现一个TableViewer(表控件)就需要一个IStructuredContentProvider,contentprovider主要的作用就是返回当前界面中的数据。

1.内容提供器(ITreeContentProvider)

TreeViewer的内容提供器(ITreeContentProvider)构建树中比较复杂的部分,它为树的显示提供了内容,内容提供器要实现的方法如下。

(1)getElements。

此函数定义为“public Object[] getElements(Object inputElement);”,当程序开始构建树时,首先调用getElements返回一个对象的数组,此数组对象表示当前树的根节点,inputElement参数为TreeViewer的输入(setInput的输入数据)。

(2)hasChildren。

此函数定义为“public boolean hasChildren(Object element);”,当TreeViewer显示一个节点后,会调用hasChildren函数判断当前节点是否有子节点,如果有子节点则显示“+”,element参数为要判断是否有子节点的节点。

(3)getChildren。

此函数定义为“public Object[] getChildren(Object parentElement);”,当用户选择节点打开子节点时,会调用getChildren函数返回下一层子节点,parentElement参数为选择的节点。

(4)getParent。

此函数定义为“public Object getParent(Object element);”,可以通过此方法返回element的父节点。

(5)inputChanged。

此函数定义为“public void inputChanged(Viewer viewer, Object oldInput, Object newInput);”,当输入改变时调用此方法。

(6)dispose。

此函数定义为“public void dispose();”,当树销毁时被调用。

其中,getElements、hasChildren和getChildren是常用的方法,用户通过重写这几种方法构建一棵树,过程如下:通过getElements方法得到根,再通过hasChildren判断根下是否有子节点,如果有子节点,可以通过getChildren得到所有的子节点。如例程15-2为ITreeContentProvider接口的一个简单实现。

例程15-2  FileTreeContentProvider.java

class FileTreeContentProvider implements ITreeContentProvider {

public Object[] getChildren(Object arg0) {
//返回树的下一级节点
return ((File) arg0).listFiles();
}

public Object getParent(Object arg0) {
//返回树的上一级节点 
return ((File) arg0).getParentFile();
}

public boolean hasChildren(Object arg0) {
Object[] obj = getChildren(arg0);

//判断树是否有下一级节点,true为在节点显示"+"信息
return obj == null ? false : obj.length > 0;
}

public Object[] getElements(Object arg0) {

//打印出树的输入信息,通常用户可以通过输入信息构建树
System.out.println(arg0);
// File.listRoots()作为树的根节点
return File.listRoots();
}
上例内容提供器通过文件系统获得树的输入内容,从而使用户构造的树能显示磁盘文件的树结构。

2.标签提供器(ILabelProvider)

在TreeViewer中,通过标签提供器(ILabelProvider)来显示节点的相关信息,包括显示内容和图标。

ILabelProvider主要实现getImage和getText函数。当TreeViewer得到一个节点后会通过getText得到此节点的显示文本,通过getImage方法得到节点的显示图标,代码如例程15-3所示。

class ViewLabelProvider extends ILabelProvider{
    …
  public String getText(Object obj) {
     return obj.toString();
  }
  public Image getImage(Object obj) {
    String imageKey = ISharedImages.IMG_OBJ_ELEMENT;
    if (obj instanceof TreeParent)
      imageKey = ISharedImages.IMG_OBJ_FOLDER;
    return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey);
  }
…
}
3.标签器还比较简单,在TreeViewer中最主要和最复杂的是内容器,熟悉内容器是掌握TreeViewer的要点。

TreeViewer内容器的代码如下:

//内容器。由它决定哪些对象记录应该输出在TreeViewer里显示
public class TreeViewerContentProvider implements ITreeContentProvider {
// 由此方法决定树的“第一级”结点显示哪些对象。inputElement是用tv.setInput()方法
//输入的那个对象。Object[]是一个数组,数组中一个元素就是一个结点
  public Object[] getElements(Object inputElement) {
    if (inputElement instanceof List) {
        List input = (List) inputElement;
        return input.toArray();
    } 
    return new Object[0]; // 空数组
  }

// 判断参数element结点是否有子结点
// 返回true表示element有子结点,则其前面会显示有“+”号图标
  public boolean hasChildren(Object element) {
    ITreeEntry entry = (ITreeEntry) element;
    List list = entry.getChildren();
    return !(list == null || list.isEmpty()); // 判断list是否有子结点
  }

// 当界面中单击某结点时,由此方法决定被单击结点应该显示哪些子结点
// parentElement就是被单击的结点对象。返回的数组就是应显示的子结点
  public Object[] getChildren(Object parentElement) {
    ITreeEntry entry = (ITreeEntry) parentElement;
    List list = entry.getChildren();
    //虽然通过界面单击方式,有子结点才会执行到此方法,但仍然要做非空判断,
    //因为在调用TreeViewer的某些方法时其内部会附带调用此方法
    if (list == null) return new Object[0]; 
    return list.toArray();
  }

// --------------以下方法暂时无用,空实现----------------
  public void dispose() {}//树被销毁时触发
  public void inputChanged(Viewer v,Object oldInput, Object newInput){} //每次tv.setInput触发
  public Object getParent(Object element) {return null;} //取得element的父结点。极少使用
}

程序说明:在内容器中最关键的是getElements、hasChildren、getChildren这3个方法。

getElements只在显示“第一级”结点时才会被执行。

hasChildren主要用于判断当前所显示的结点是否有子结点,如果有子结点则前面显示一个“+”号图标,而有“+”号的结点则可以单击展开其下一级的子结点。

当单击有“子”的结点时,才会执行getChildren方法。展开其子结点后,又会对子结点执行一遍hasChildren方法,以决定其各子结点前是否显示“+”图标。

图15.4给出了内容器在启动、单击结点、关闭窗口这3种情况时的方法执行的时序图。

下面以本实例来解释此图:

树界面启动时:先执行inputChanged方法。接着执行getElements方法,其inputElement参数就是由setInput传入的对象:包含所有实体对象的List。此List在getElements中被转化成一个数组,数组包含第一级结点的两个元素中国和美国,它们将首先显示在界面上。接下来执行两次hasChildren方法,判断中国和美国是否有子结点。它们都有子结点,故方法返回True,两结点前都显示“+”图标。

单击有子结点的中国:先执行一次getChildren方法,方法的parentElement参数就是中国结点对象。方法中把中国的子结点取出并转化成一个数组返回,此数组包含3个元素“北京、台湾、桂林”。接下来连续执行3次hasChildren方法来判断“北京、台湾、桂林”是否有子结点,如果有,则在结点前显示一个“+”图标。

单击没有子结点的桂林:不会执行内容器中的任何方法。

关闭窗口:会先后执行inputChanged和dispose方法。


Eclipse插件开发之TreeViewer,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。