首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

15.3  让数据在树中显示出来

本节实例的效果如图15.3所示。实现分以下几个步骤:

图15.3  树的效果图

15.3.1  创建树的数据结构

15.2节介绍了3个实体类的数据模型,接下来就要像第14章TableViewer的一样,用实体类来创建出各数据对象,并用集合List把国家、城市、人连接起来。和TableViewer一样,建立一个数据对象生成工厂来负责树的数据对象的创建。

public class DataFactory {

         public static List<CountryEntity> createTreeData() {

                   // 生成国家的数据对象

                   CountryEntity cn = new CountryEntity("中国");

                   CountryEntity us = new CountryEntity("美国");

                   // 生成城市的数据对象

                   CityEntity city1 = new CityEntity("北京");

                   CityEntity city2 = new CityEntity("台湾");

                   CityEntity city3 = new CityEntity("桂林");

                   CityEntity city4 = new CityEntity("芝加哥");

                   CityEntity city5 = new CityEntity("纽约");

                   {// ----------往城市加人---------------------

                            // 北京

                            ArrayList<PeopleEntity> list = new ArrayList<PeopleEntity>();

                            list.add(new PeopleEntity("陈刚"));

                            list.add(new PeopleEntity("陈知行"));

                            list.add(new PeopleEntity("韩立新"));

                            city1.setChildren(list);

                            // 台湾

                            list = new ArrayList<PeopleEntity>();

                            list.add(new PeopleEntity("桃子"));

                            list.add(new PeopleEntity("林雅仕"));

                            list.add(new PeopleEntity("陈常恩"));

                            city2.setChildren(list);

                            // 纽约

                            list = new ArrayList<PeopleEntity>();

                            list.add(new PeopleEntity("Giles"));

                            list.add(new PeopleEntity("Tom"));

                            list.add(new PeopleEntity("Rose"));

                            city5.setChildren(list);

                   }

                   {// ---------城市和国家的关系------------------

                            // 北京、台湾、桂林属于中国

                            ArrayList<CityEntity> list = new ArrayList<CityEntity>();

                            list.add(city1);

                            list.add(city2);

                            list.add(city3);

                            cn.setChildren(list);

                            // 芝加哥、纽约属于美国

                            list = new ArrayList<CityEntity>();

                            list.add(city4);

                            list.add(city5);

                            us.setChildren(list);

                   }

                   {// 将所有国家放于一个集合中,也可以放到一个数组中

                            ArrayList<CountryEntity> list = new ArrayList<CountryEntity>();

                            list.add(cn);

                            list.add(us);

                            return list;

                   }

         }

}

15.3.2  创建主程序

和TableViewer一样,TreeViewer也是用内容器和标签器来控制记录对象的显示,并且使用内容器和标签器的语句也一样。TreeViewer的主程序如下所示,它还是沿用了旧的SWT程序的代码框架,唯一的变化是单独封到了一个非静态方法中。

public class TreeViewer1 {

         public static void main(String[] args) {      new TreeViewer1().open();       }

         public void open() {

                   final Display display = new Display();

                   final Shell shell = new Shell();

                   shell.setSize(200, 300);

                   // -----------界面核心代码-------------------

                   shell.setLayout(new FillLayout());

                   TreeViewer tv = new TreeViewer(shell, SWT.BORDER);

                   tv.setContentProvider(new TreeViewerContentProvider());

                   tv.setLabelProvider(new TreeViewerLableProvider());

                   // 和TableViewer一样,数据的入口也是setInput方法

                   List<CountryEntity> input = DataFactory.createTreeData();

                   tv.setInput(input);

                   // -----------END------------------

                   shell.open();

                   while (!shell.isDisposed()) {

                            if (!display.readAndDispatch())

                                     display.sleep();

                   }

                   display.dispose();

         }

}

15.3.3  标签器(实现ILabelProvider接口)

将标签器写成单独的外部类,以便于后面的实例共用,其代码如下。在getText方法中element的类型可能是国家、城市、人,由于它们都属于一个接口,所以getText的代码简洁不少。getImage()的实现参考TableViewer的标签器。

//标签器。控制结点在树中显示的文字和图像等

public class TreeViewerLableProvider implements ILabelProvider {

         // 结点显示的文字。不能返回null值

         public String getText(Object element) {

                   ITreeEntry entry = (ITreeEntry) element;

                   return entry.getName();

         }

         // 结点显示的图像,可以返回null值

         public Image getImage(Object element) {                  return null;        }

         // --------以下方法暂不用,空实现----------

         public void addListener(ILabelProviderListener listener) {}

         public void removeListener(ILabelProviderListener listener) {}

         public void dispose() {}

         public boolean isLabelProperty(Object e, String p) {          return false;     }

}

15.3.4  内容器(实现ITreeContentProvider接口)

标签器还比较简单,在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种情况时的方法执行的时序图。

图15.4  内容器的方法的时序图

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

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

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

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

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

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论