博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Eclipse中的TreeViewer类和ListViewer类
阅读量:5049 次
发布时间:2019-06-12

本文共 20618 字,大约阅读时间需要 68 分钟。

TreeViewer和TableViewer在使用上还是有很多相似之处.TreeViewer中冶有TableViewer中的过滤器和排序器.具体使用看TableViewer中的使用.

和Table有JFace的扩展TableViewer一样,Tree也有一个JFace中的扩展,那就是TreeViewer.因为TreeViewer和TableViewer继承自同一个父类StructuredViewer所以两者有很多方法的使用是一样的.例如:都使用setInput方法输入数据,都有内容器,标签器,以及排序器,过滤器等.

建立一个树节点的接口类:

树节点由两个基本特征,名称和子节点.这里把这两个特征抽象出来写成一个接口,然后将要做树节点的实体类实现此接口.

主义这个接口不是必须的.仅仅是为了今后操作方便,以及规范化涉及才建立的.

但是每个实体对应的都是树上的一个节点.这里定义一个树中节点的通用接口.

然后每个实体类都实现这个接口.

接着建立几个实体类:

ITreeEntry.java

1 /** 2  * 树上的每个一个节点都对应的是一个实体,这个实体是树上的一个节点. 3  * 首先在定义实体类(People City Country)之前要先定义这个接口ITreeEntry 4  * 树的节点接口 5  * @author kongxiaohan 6  */ 7 public interface ITreeEntry { 8     /* 9      * 设置dedao 树节点的名称    10      * 只声明抽象方法,不声明字段名11      */12     public String getName();13     public void setName(String name);14     15     16     /*17      * 设置与得到子节点集合.18      */19     public void setChildren(List
children);20 public List
getChildren();21 }

City.java

1 /** 2  * City城市实体类 3  * @author kongxiaohan 4  * 5  */ 6 public class City implements ITreeEntry{ 7     private Long id; // 唯一识别码,在数据库里常为自动递增的ID列 8     private String name;// 城市名 9     10     private List
peoples;//City实体的子节点 城市中的人,装在一个List集合中11 12 public City(String name) {13 super();14 this.name = name;15 }16 17 public Long getId() {18 return id;19 }20 public void setId(Long id) {21 this.id = id;22 }23 public String getName() {24 return name;25 }26 public void setName(String name) {27 this.name = name;28 }29 30 //这个地方是设置子节点....当前是City实体,其子节点是People实体31 @Override32 public void setChildren(List
children) {33 //这个地方我犯了一错误,以前写习惯了,this.name = name34 //所以一开始这个地方我写的是this.peoples = peoples 35 //在Country实体类中也是这个错误,所以运行出来的程序只有一列国家名,国家下面的城市都没有了....36 this.peoples = children;37 }38 39 @Override40 public List
getChildren() {41 return peoples;42 }43 }

Country.java

1 /** 2  * Country国家实体类 3  * @author kongxiaohan 4  */ 5 public class Country implements ITreeEntry { 6     private Long id; // 唯一识别码,在数据库里常为自动递增的ID列 7     private String name; // 国家名 8      9     private List
cities; //Country实体的子节点是城市 City 此国家所包含的的城市的集合,集合元素为City对象10 11 public Country() {12 }13 14 public Country(String name) {15 super();16 this.name = name;17 }18 19 public Long getId() {20 return id;21 }22 public void setId(Long id) {23 this.id = id;24 }25 public String getName() {26 return name;27 }28 public void setName(String name) {29 this.name = name;30 }31 32 @Override33 public void setChildren(List
children) {34 this.cities = children;35 }36 37 @Override38 public List
getChildren() {39 return cities;40 }41 }

People.java

1 public class People implements ITreeEntry { 2     private Long id; // 唯一识别码,在数据库里常为自动递增的ID列 3     private String name; // 姓名 4     private boolean sex; // 性别 true男,flase女 5     private int age; // 年龄 6     private Date createDate; // 记录的建立日期,是java.util.Date,而不是java.sql.Date 7  8     public People(String name) { 9         super();10         this.name = name;11     }12     public Long getId() {13         return id;14     }15     public void setId(Long id) {16         this.id = id;17     }18     public String getName() {19         return name;20     }21     public void setName(String name) {22         this.name = name;23     }24     public boolean isSex() {25         return sex;26     }27     public void setSex(boolean sex) {28         this.sex = sex;29     }30     public int getAge() {31         return age;32     }33     public void setAge(int age) {34         this.age = age;35     }36     public Date getCreateDate() {37         return createDate;38     }39     public void setCreateDate(Date createDate) {40         this.createDate = createDate;41     }42     43     44     //因为人是这个树的最小子节点,所以这个地方空实现接口中的这两个方法就可以了45     @Override46     public void setChildren(List
children) {47 }48 @Override49 public List
getChildren() {50 return null;51 }52 }

制造各个实体类的工具类

DataFactory.java

1 /** 2  * 此类负责生成TreeViewer的方法setInput所需要的参数. 3  * @author kongxiaohan 4  *  5  * 这个地方我没有用书中用的局部代码块,在组织代码的时候确实犯了一些小错误, 6  * 确实体会到了局部代码块的意义,代码读起来容易,而且节省了内存. 7  */ 8 public class DataFactory { 9     /**10      * 在这个方法中定义生成的数据11      * 要有人People的数据对象12      * 要有国家Country的数据对象13      * 要有城市City的数据对象14      * @return15      */16     public static Object createTreeData(){17         //生成人People的数据对象18         People people1 = new People("张A");19         People people2 = new People("张B");20         People people3 = new People("张C");21         People people4 = new People("张D");22         People people5 = new People("张E");23         People people6 = new People("张F");24         People people7 = new People("张G");25         People people8 = new People("张H");26         People people9 = new People("张I");27         28         //生成城市City的数据对象29         City city1 = new City("北京");30         City city2 = new City("广州");31         City city3 = new City("东京");32         City city4 = new City("芝加哥");33         City city5 = new City("洛杉矶");34         35         //生成国家Country的的数据对象36         Country country1 = new Country("中国");37         Country country2 = new Country("日本");38         Country country3 = new Country("美国");39         40         /**41          * 将这些封装的对象建立关系.42          */43         //1.人和城市的关系 44         //张A 张B 张C 在帝都45         ArrayList
list1 = new ArrayList
();46 list1.add(people1);47 list1.add(people2);48 list1.add(people3);49 city1.setChildren(list1);50 51 //张D 张E 张F在广州 52 ArrayList
list2 = new ArrayList
();53 list2.add(people4);54 list2.add(people5);55 list2.add(people6);56 city2.setChildren(list2); 57 58 //张G 在东京59 ArrayList
list3 = new ArrayList
();60 list3.add(people7);61 city3.setChildren(list3); 62 63 //张I 在芝加哥64 ArrayList
list4 = new ArrayList
();65 list4.add(people8);66 city4.setChildren(list4); 67 68 //张H 在洛杉矶69 ArrayList
list5 = new ArrayList
();70 list5.add(people9);71 city5.setChildren(list5); 72 73 //2.城市和国家的关系74 //北京 上海 广州是中国的75 ArrayList
list6 = new ArrayList
();76 list6.add(city1);77 list6.add(city2);78 country1.setChildren(list6);79 80 //东京是日本的81 ArrayList
list7 = new ArrayList
();82 list7.add(city3);83 country2.setChildren(list7);84 85 //芝加哥和洛杉矶是美国的86 ArrayList
list8 = new ArrayList
();87 list8.add(city4);88 list8.add(city5);89 country3.setChildren(list8);90 91 //3.将国家置于一个对象之下,这个对象可以是一个List也可以是个数组92 //国家是这个树上的最上层的节点.国家和国家之间是并列的关系,把这几个国家放到一个List集合对象中.93 ArrayList
list9 = new ArrayList
();94 list9.add(country1);95 list9.add(country2);96 list9.add(country3);97 return list9;98 }99 }

内容器:TreeViewerContentProvider.java

标签器还比较简单,在TreeViewer中最主要和最复杂的是内容器,熟悉内容器是掌握TreeViewer的要点.

1 /** 2  * "内容器" 由它决定哪些对象记录应该输出在TreeViewer里显示. 3  * @author kongxiaohan 4  * 5  */ 6 public class TreeViewerContentProvider  implements ITreeContentProvider{ 7  8     /** 9      * 这个方法决定树的一级目录显示哪些对象10      * @param inputElement 是用tv.setInput()方法输入的那个对象11      * @return Object[]一个数组,数组中一个元素就是一个结点12      */13     @Override14     public Object[] getElements(Object inputElement) {15         if (inputElement instanceof List) {16             List list = (List) inputElement;17             return list.toArray();18         } else {19             return new Object[0]; // 生成一个空数组20         }21     }22     23     24     /**25      * 判断某结点是否有子结点。如果有子结点,这时结点前都有一个“+”号图标26      * 27      * @param element 需要判断是否有子的结点28      * @return true有子结点,false无子结点29      */30     @Override31     public boolean hasChildren(Object element) {32         ITreeEntry entry = (ITreeEntry) element;33         List
list = entry.getChildren();34 if (list == null || list.isEmpty()) {35 return false;36 } else {37 return true;38 }39 }40 41 42 /**43 * 由这个方法决定父结点应该显示那些子结点。44 * 45 * @param parentElement 当前被点击的结点对象46 * @return 由子结点做为元素的数组47 */48 @Override49 public Object[] getChildren(Object parentElement) {50 ITreeEntry entry = (ITreeEntry) parentElement;51 List
list = entry.getChildren();52 if (list == null || list.isEmpty()) {53 return new Object[0];54 } else {55 return list.toArray();56 }57 }58 59 //>>>>>>>>>>>>>>>>>>>>>>>>>书上说以下三个方法是没有用的,空实现就哦了>>>>>>>>>>>>>>>>>>>>>>60 @Override61 public Object getParent(Object element) {62 return null;63 }64 65 @Override66 public void dispose() {67 }68 69 @Override70 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {71 }72 }

程序说明:在内容器中最关键的是getElements,hasChildren,getChildren这三个方法.

1.getElements自在显示"第一级"结点的时候才会被执行.

2.hasChildren主要用于判断当前说系那是的节点是否有子节点,如果有子节点则前面显示一个"+"号图标,而有"+"号的结点则可以单击展开其下一级的子节点.

3.当单击右"子"的结点的时候,才会执行getChildren方法.展开其子节点后,又会对子节点执行一遍hasChildren方法,以决定其各子结点前是否显示"+"图标.

下面是"内容器"在启动,单击,关闭窗口时执行的过程.

下面以本例来解释这个图:

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

2.单击右子节点的中国:先执行一次getChildren方法,方法的parentElement参数就是中国结点对象.方法中把中国的子节点取出转换陈给一个数组返回,此数组包含3个元素"北京,上海,济南".接下来连续执行3次hasChildren方法来判断"北京,上海,济南"是否有子节点,如果有在结点的前面显示一个"+"图标.

3.单击没有子节点的结点:不会有执行内容器中的任何方法.

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

 

标签器TreeViewerLableProvider.java

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

1 /** 2  * "标签器" 控制记录在树中显示的文字和图像等. 3  * @author kongxiaohan 4  */ 5 public class TreeViewerLableProvider implements ILabelProvider { 6  7     /** 8      * 记录显示的文字。不能返回NULL值 9      */10     @Override11     public String getText(Object element) {12         //得到这个节点对应的名字,首先对element进行强制类型转换13         ITreeEntry entry = (ITreeEntry) element;14         return entry.getName();15     }16     17     /**18      * 记录显示的图像,可以返回NULL值19      */    20     @Override21     public Image getImage(Object element) {22         return null;23     }24     25 //>>>>>>>>>>>>>>>>>>>>>>书上说一下几个方法没有用,空实现就可以了.>>>>>>>>>>>>>>>>>>>>>>>>>    26     @Override27     public void addListener(ILabelProviderListener listener) {28         // TODO Auto-generated method stub29         30     }31 32     @Override33     public void removeListener(ILabelProviderListener listener) {34         // TODO Auto-generated method stub35         36     }37     @Override38     public void dispose() {39         // TODO Auto-generated method stub40         41     }42     @Override43     public boolean isLabelProperty(Object element, String property) {44         // TODO Auto-generated method stub45         return false;46     }47 }

给TreeViewer加上右键菜单的方法和TableViewer相似,也要用到Action,ActionGroup,MenuManager类.当然程序要根据树的特点稍作改动.

MyActionGroup内含有各Action类,在实现Action时,对传入的结点对象要记得进行空值判断.因为TreeViewer的大部分方法都不支持空值参数.会导致异常并中断程序.

MyActionGroup.java

1 public class MyActionGroup extends ActionGroup {  2     //ActionGroup这是个抽象类,但是其中并没有抽象方法.  3     private TreeViewer treeViewer;  4   5     //构造方法  6     public MyActionGroup(TreeViewer treeViewer) {  7         this.treeViewer = treeViewer;  8     }  9      10     /** 11      * 生成菜单Menu,并将两个Action传入 12      */ 13     public void fillContextMenu(IMenuManager mgr) { 14         /* 15          * 加入两个Action对象到菜单管理器 16          */ 17         MenuManager menuManager = (MenuManager) mgr; // 把接口类转换成其实现类. 18         //用MenuManager管理Action 19         menuManager.add(new OpenAction()); 20         menuManager.add(new RefreshAction()); 21         menuManager.add(new ExpandAction()); 22         menuManager.add(new CollapseAction()); 23         menuManager.add(new AddEntryAction()); 24         menuManager.add(new RemoveEntryAction()); 25         menuManager.add(new ModifyEntryAction()); 26         /* 27          * 把这些功能加入到右键的Menu菜单中. 28          */ 29         Tree tree = treeViewer.getTree(); 30         Menu menu = menuManager.createContextMenu(tree); 31         tree.setMenu(menu); 32     } 33      34     /** 35      * 打开"菜单"对应的Action类 36      */ 37     private class OpenAction extends Action { 38         public OpenAction() { 39             setText("打开"); 40         } 41         /** 42          * 继承自Action的方法,动作代码写此方法中 43          */ 44         //覆盖Action中的run()方法. 45         public void run() { 46             ITreeEntry obj = getSelTreeEntry();//getgetSelTreeEntry()得到当前节点 47             if (obj != null) { 48                 //弹出一个这个节点名字的对话框. 49                 MessageDialog.openInformation(null, null, obj.getName()); 50             } 51         } 52     } 53      54     /** 55      * 刷新对应的Action类. 56      */ 57     private class RefreshAction extends Action { 58         public RefreshAction() { 59             setText("刷新"); 60         } 61  62         //覆盖Action类中的run()方法,里面是调用的refresh()方法. 63         public void run() { 64             treeViewer.refresh();// 调用TreeViewer的刷新方法 65         } 66     } 67  68     /** 69      * 展开当前结点的Action类 70      */ 71     private class ExpandAction extends Action { 72         public ExpandAction() { 73             setText("展开"); 74         } 75         //重写run()方法 76         public void run() { 77             ITreeEntry obj = getSelTreeEntry(); 78             if (obj != null) { 79                 treeViewer.expandToLevel(obj, 1);  80                 // 这个方法后面的数字是展开的层级数.这个地方设置成仅仅展开1个层级. 81             } 82         } 83     } 84  85     /** 86      * 收缩当前结点的Action类 87      */ 88     private class CollapseAction extends Action { 89         public CollapseAction() { 90             setText("收缩"); 91         } 92         //重写run()方法 93         public void run() { 94             ITreeEntry obj = getSelTreeEntry(); 95             if (obj != null) { 96                 treeViewer.collapseToLevel(obj, -1); // -1为将当前结点的所有子结点收缩 97             } 98         } 99     }100 101     /**102      * 给当前结点增加一个子结点的Action类103      */104     private class AddEntryAction extends Action {105         public AddEntryAction() {106             setText("增加");107         }108         @Override109         public void run() {110             ITreeEntry obj = getSelTreeEntry();111             if (obj == null || obj instanceof People) {112                 return;113             }114             InputDialog dialog = new InputDialog(null, "给当前结点增加一个子结点", "输入名称", "请输入你要增加的节点的名字", null);115             if (dialog.open() == InputDialog.OK) {
// 如果单击OK按钮116 String entryName = dialog.getValue(); // 得到Dialog输入值117 /* 根据单击结点的不同类型生成相应的子结点 */118 ITreeEntry newEntry = null;119 if (obj instanceof Country) {120 newEntry = new City(entryName);121 } else if (obj instanceof City) {122 newEntry = new People(entryName);123 }124 /* 在增加子结点之前将父结点展开 */125 if (!treeViewer.getExpandedState(obj)) {126 treeViewer.expandToLevel(obj, 1);127 }128 treeViewer.add(obj, newEntry);// 增加结点129 }130 }131 }132 133 /**134 * 删除结点的Action类135 */136 private class RemoveEntryAction extends Action {137 public RemoveEntryAction() {138 setText("删除");139 }140 @Override141 public void run() {142 ITreeEntry obj = getSelTreeEntry();143 if (obj == null) {144 return;145 }146 treeViewer.remove(obj);147 }148 }149 150 /**151 * 修改结点名称的Action类152 */153 private class ModifyEntryAction extends Action {154 public ModifyEntryAction() {155 setText("修改");156 }157 @Override158 public void run() {159 ITreeEntry obj = getSelTreeEntry();160 if (obj == null) {161 return;162 }163 InputDialog dialog = new InputDialog(null, "修改结点", "输入新名称", obj.getName(), null);164 if (dialog.open() == InputDialog.OK) {165 String entryName = dialog.getValue();//得到对话框中的值.166 obj.setName(entryName);//给这个节点设置成得到的对话框中的名字.167 treeViewer.refresh(obj); // 刷新结点168 }169 }170 }171 /**172 * 这个方法是自定义的方法,这个方法的作用就是得到当前选择的节点.173 */174 private ITreeEntry getSelTreeEntry() {175 IStructuredSelection selection = (IStructuredSelection) treeViewer.getSelection();176 ITreeEntry treeEntry = (ITreeEntry) (selection.getFirstElement());177 return treeEntry;178 }179 }

TreeViewer.java的实例

1 public class TreeViewer1 { 2     public static void main(String[] args) { 3         TreeViewer1 window = new TreeViewer1(); 4         window.open(); 5     } 6      7     //定义这个open()方法.就是创建一个典型的SWT程序的步骤 8     public void open(){ 9         //1.Display负责管理一实现循环和控制UI线程和其他线程之间的通信10         final Display display = new Display();11         //2.创建一个或者多个Shell(shell是程序的主窗口)12         final Shell shell = new Shell();13         //3.设置shell的布局.14         shell.setSize(200, 300);15         //设置shell的布局为FillLayout16         shell.setLayout(new FillLayout());17         shell.setText("TreeViewer的第一个例子");18         19         20         Composite c = new Composite(shell, SWT.NONE);21         c.setLayout(new FillLayout());22         TreeViewer treeViewer = new TreeViewer(c, SWT.BORDER);23         treeViewer.setContentProvider(new TreeViewerContentProvider());24         treeViewer.setLabelProvider(new TreeViewerLableProvider());25         // 和TableViewer一样,数据的入口也是setInput方法26         Object inputObj = DataFactory.createTreeData();27         treeViewer.setInput(inputObj);28         29         /*30         //调用自定义的方法创建表格31         createTableViewer(shell);32         //4.设定内容器33         tableviewer.setContentProvider(new TableViewerContentProvider());34         //5.设定标签器35         tableviewer.setLabelProvider(new TableViewerLabelProvider());36         //6.用setInput输入数据(把PeopleFactory产生的List集合传进来)37         tableviewer.setInput(PeopleFactory.getPeoples());38         */39         40         //7.创建Shell中的组件(这个例子中没有加入组件,只有一个空窗口)41         shell.open();42         //8.写一个时间转发循环43         while(!shell.isDisposed()){
//如果主窗口没有关闭,则一直循环44 //dispose 是"处理,处置,毁掉"的意思45 if(!display.readAndDispatch()){
如果display不忙46 display.sleep();// display休眠47 }48 }49 }50 }

TreeViewer1.java的运行结果图

TreeViewer2.java

1 public class TreeViewer2 { 2  3     public static void main(String[] args) { 4         TreeViewer2 window = new TreeViewer2(); 5         window.open(); 6     } 7      8     public void open() { 9         final Display display = new Display();10         final Shell shell = new Shell();11         shell.setSize(200, 300);12 13         shell.setLayout(new FillLayout());14         Composite c = new Composite(shell, SWT.NONE);15         c.setLayout(new FillLayout());16         TreeViewer treeViewer = new TreeViewer(c, SWT.BORDER);17         treeViewer.setContentProvider(new TreeViewerContentProvider());18         treeViewer.setLabelProvider(new TreeViewerLableProvider());19         Object inputObj = DataFactory.createTreeData();20         //>>>>>>>>>>>>>相比于TreeViewer1.java增加的>>>>>>>>>>>>>>>>>>>>>>>>>21         //生成一个ActionGroup对象22         MyActionGroup actionGroup = new MyActionGroup(treeViewer);23         // 调用fillContextMenu方法将按钮注入到菜单对象中24         actionGroup.fillContextMenu(new MenuManager());25         // --------------加入代码:END--------------------26         treeViewer.setInput(inputObj);27         // -----------------------------28         shell.open();29         while (!shell.isDisposed()) {30             if (!display.readAndDispatch()) {31                 display.sleep();32             }33         }34     }35 }

TreeViewer2.java的运行结果图:

 上面的这个是<<Eclispe从入门到精通>>中第一版的代码,在第二版中对一些功能进行了一些改进.

该进在于"不同的结点显示不同的菜单".

树的"人"结点是没有子节点的.因此对于"人"这个节点来说,右键菜单中的"展开,收缩,增加"菜单项都没有任何意义,应该隐藏起来,再根据当前节点的类型决定要将哪些Action加入菜单中.按着这个思路将MyActionGroup类的fillContextMenu方法修改如下:

 

转载于:https://www.cnblogs.com/DreamDrive/p/4178096.html

你可能感兴趣的文章
Oracle数据库的增、删、改、查
查看>>
MySql执行分析
查看>>
git使用中的问题
查看>>
yaml文件 .yml
查看>>
linux字符集修改
查看>>
phpcms 添加自定义表单 留言
查看>>
mysql 优化
查看>>
读书笔记 ~ Nmap渗透测试指南
查看>>
WCF 配置文件
查看>>
动态调用WCF服务
查看>>
oracle导出/导入 expdp/impdp
查看>>
类指针
查看>>
css修改滚动条样式
查看>>
2018.11.15 Nginx服务器的使用
查看>>
Kinect人机交互开发实践
查看>>
百度编辑器UEditor ASP.NET示例Demo 分类: ASP.NET...
查看>>
JAVA 技术类分享(二)
查看>>
android客户端向服务器发送请求中文乱码的问
查看>>
Symfony翻译教程已开课
查看>>
TensorFlow2.0矩阵与向量的加减乘
查看>>