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方法。