SWT表格TableViewer类.docx
《SWT表格TableViewer类.docx》由会员分享,可在线阅读,更多相关《SWT表格TableViewer类.docx(41页珍藏版)》请在冰点文库上搜索。
![SWT表格TableViewer类.docx](https://file1.bingdoc.com/fileroot1/2023-4/29/75486686-9261-45c4-8fad-3801763d9b6f/75486686-9261-45c4-8fad-3801763d9b6f1.gif)
SWT表格TableViewer类
SWT-------表格(TableViewer类)_1
2011-09-1515:
56
第14章表格(TableViewer类)
TableViewer表格类是JFace组件中重要且典型的一个组件,其中涉及了JFace的众多重要概念:
内容器、标签器、过滤器、排序器和修改器,这些概念对后面JFace组件特别是TreeViewer的学习非常重要。
从本章也可以体会到JFace非常突出的面向对象特性。
14.1概述
JFace是SWT的扩展,它提供了一组功能强大的界面组件,其中包含表格、树、列表、对话框、向导对话框等,从本章之后就开始专门来介绍这些JFace组件。
表格是一种在软件系统很常见的数据表现形式,特别是基于数据库的应用系统,表格更是不可缺少的界面组件。
SWT的表格组件(Table类)前面已经介绍过了,但在实际项目开发中一般还是用JFace的表格组件TableViewer比较多。
TableViewer组件是在SWT的Table组件基础上采用MVC模式扩展而来的,但Table并非TableViewer的父类,从图14.1两个类的谱系图就可以看出这两个类不属于同一族系。
从下面的TableViewer类源代码可以看到,TableViewer把Table作为一个实例变量,从而实现了对Table功能的扩展。
publicclassTableViewerextendsStructuredViewer{
privateTableViewerImpltableViewerImpl;
privateTabletable;//把Table类作为一个实例变量
privateTableEditortableEditor;
……
}
本章就如何使用表格组件TableViewer类来展开讲解,并通过一步步地创建一个完整的表格应用实例来串起表格的知识点,实例的最后界面如图14.2所示。
图14.1谱系图
图14.2本章实例的最后界面
14.2创建表格并显示数据
作为起步,本节将演示如何创建一个TableViewer对象,如何用TableViewer来显示数据记录,实例运行效果如图14.3所示。
图14.3TableViewer效果图
14.2.1实例的数据模型介绍
本实例用TableViewer来显示一个数据表中的3条记录,每一条记录对应某一个人的基本资料,记录有5个字段:
ID号(数值型)、姓名(字符型)、性别(布尔型)、年龄(数值型)和记录建立时间(日期型)。
如何在程序中体现和操作这些数据记录呢?
在过去,像ASP、PHP这类面向过程的编程模式,人们习惯了这样操作数据:
从数据库中读取数据,并不对数据做任何封装,直接将数据一条条地显示在表格中。
现在用Java这种面向对象的编程语言,应该用更规范的方式来操作数据:
将数据库中的记录看作一个数据对象,用一个类来表示它,数据表的字段写成类的实例变量,这样的类在Java中叫做实体类(或称数据类)。
EJB和Hibernate的数据操作方式都是这样的。
数据库与表格显示之间加上了实体类,如此一来,以前的“数据表→表格显示”方式就分成了两个步骤“数据库→实体类→表格显示”。
有些习惯了以前编程方式的人也许会觉得多了一个步骤太麻烦,但其实这种方式很有好处:
表格显示的代码不再和数据库表相关。
例如,将数据库由Oracle移植到MySQL时就不需要更改“数据库→实体类”这个环节的代码。
零散的字段变量统一在一个类中,程序代码结构更紧凑、清晰,有利于今后代码的维护。
不要小看维护问题,很多系统做好后不敢再改,害怕改动后会牵涉到其他模块,其中原因之一就是代码结构太乱、编程不规范所致。
将数据封装在一个实体类中,在数据传递时方便许多,可以将实体类作为一个参数在方法与方法之间来回传递。
14.2.2创建数据表的实体类
下面依照表中的字段来创建一个相应的实体类,类名为PeopleEntity,代码如下所示。
//-------------文件名:
PeopleEntity.java--------------
//本类包含5个不同数据类型的变量,分别对应数据库表中的5个字段。
变量为private型,即只能
//由类的内部代码访问,外界只能通过这些变量相应的Setter/Getter方法来访问它们
publicclassPeopleEntity{
privateLongid;//唯一识别码,在数据库里常为自动递增的ID列
privateStringname;//姓名
privatebooleansex;//性别true男,flase女
privateintage;//年龄
privateDatecreateDate;//记录的建立日期。
Date类型是java.util.Date,而不是java.sql.Date
//以下代码为字段各自的Setter/Getter方法。
参考第3.5.2节,这些方法在Eclipse可自动生成
publicLonggetId(){returnid;}
publicvoidsetId(Longlong1){id=long1;}
publicStringgetName(){returnname;}
publicvoidsetName(Stringstring){name=string;}
publicbooleanisSex(){returnsex;}
publicvoidsetSex(booleansex){this.sex=sex;}
publicintgetAge(){returnage;}
publicvoidsetAge(inti){age=i;}
publicDategetCreateDate(){returncreateDate;}
publicvoidsetCreateDate(Datedate){createDate=date;}
}
14.2.3数据的生成
由于数据操作是分两步走:
“数据库→实体类→表格显示”,实体类隔离了代码对数据库的依赖,所以“数据库→实体类”这一步就不再讲解,这部分的代码与JFace组件的使用无关紧要,也不会影响表格组件的讲解。
关于TableViewer和数据库结合使用方面的内容,在后面“插件项目实战”中会有详细示例。
那么如何生成实体类的对象呢?
因为数据记录和实体对象相对应,新创建的实体对象就相当于一个空记录,可以用其set方法一个个地将值设入实体对象中,这样就能得到带有数据的实体对象了。
为了今后便于扩展,将创建实体对象的方法集中在一个类中,这种专门负责创建对象的类又叫对象工厂。
此类的代码如下:
//-----------文件名:
PeopleFactory.java----------------
//创建PeopleEntity对象的工厂,创建3个PeopleEntry对象,并装入List集合返回
publicclassPeopleFactory{
publicstaticListgetPeoples(){//工厂的静态方法
Listlist=newArrayList();
{//第1个实体类对象
PeopleEntityo=newPeopleEntity();
o.setId(newLong
(1));//id字段的类型被定义成了Long,所以要转化一下
o.setName("陈刚");
o.setSex(true);
o.setAge(28);
o.setCreateDate(newDate());//当前日期
list.add(o);
}
{//第2个实体类对象
PeopleEntityo=newPeopleEntity();
o.setId(2L);//利用JDK5.0的自动装箱功能,省了long到Long对象的转化
o.setName("周阅");
o.setSex(false);
o.setAge(18);
o.setCreateDate(newDate());
list.add(o);
}
{//第3个实体类对象
PeopleEntityo=newPeopleEntity();
o.setId(3L);
o.setName("陈常恩");
o.setSex(true);
o.setAge(27);
o.setCreateDate(newDate());
list.add(o);
}
returnlist;
}
}
程序说明:
在实际应用中,getPeoples方法可由硬性生成PeopleEntity对象,改为从数据库中取出数据后生成PeopleEntity对象。
这里的List不是SWT组件的List,而是Java的集合类java.util.List。
根据实际开发情况也可以用数组或Set、Map等代替List。
List是接口,而ArrayList是实际用的类。
由于其后代码是基于List接口编写的,所以换用其他List接口的实现类,如Vector、LinkedList等,而不必修改其后的代码。
面向接口编程,尽量让定义类型(如List)比实际类型(如ArrayList)更宽泛些,有利于以后的修改维护。
这里newArrayList()使用了JDK5.0的泛型功能,关于泛型可参阅上的Java类文章。
在数据库编程中,Java集合类起着重要作用。
一定要很熟悉各集合类在特性上的差别,这样才能根据实际开发情况作出适当的选择(集合类的详细资料可查阅Java基础书籍)。
SWT-------表格(TableViewer类)_2
14.2.4在表格中显示数据
在得到由List装载的包含数据信息的实体类对象后,接下来就是使用TableViewer来显示这些数据,实现过程一般要经过如下步骤:
第一步:
创建一个TableViewer对象,并在构造函数中用式样设置好表格的外观,这与其他SWT组件的用法一样。
第二步:
通过表格内含的Table对象设置布局方式,一般都使用TableViewer的专用布局管理器TableLayout。
该布局方式将用来管理表格内的其他组件(如TableColumn表格列)。
第三步:
用TableColumn类创建表格列。
第四步:
设置内容器和标签器。
内容器和标签器是JFace组件中的重要概念,它们分别是IStructuredContentProvider、ITableLabelProvider两个接口的实现类,它们的作用就是定义好数据应该如何在TableViewer中显示。
第五步:
用TableViewer的setInput方法将数据输入到表格。
就像人的嘴巴,setInput就是TableViewer的嘴巴。
图14.4是TableViewer整个数据流程的示意图。
图14.4TableViewer数据流程示意图
程序代码如下(内容器和标签器写成两个单独的类):
//-------------文件名:
TableViewer1.java-------------------
shell.setLayout(newFillLayout());
//第一步:
创建一个TableViewer对象。
式样:
MULTI可多选、H_SCROLL有水平滚动条、V_SCROLL
//有垂直滚动条、BORDER有边框、FULL_SELECTION整行选择
TableViewertv=newTableViewer(shell,SWT.MULTI|SWT.BORDER|SWT.FULL_SELECTION);
//第二步:
通过表格内含的Table对象设置布局方式
Tabletable=tv.getTable();
table.setHeaderVisible(true);//显示表头
table.setLinesVisible(true);//显示表格线
TableLayoutlayout=newTableLayout();//专用于表格的布局
table.setLayout(layout);
//第三步:
用TableColumn类创建表格列
layout.addColumnData(newColumnWeightData(13));//ID列宽13像素
newTableColumn(table,SWT.NONE).setText("ID号");
layout.addColumnData(newColumnWeightData(40));
newTableColumn(table,SWT.NONE).setText("姓名");
layout.addColumnData(newColumnWeightData(20));
newTableColumn(table,SWT.NONE).setText("性别");
layout.addColumnData(newColumnWeightData(20));
newTableColumn(table,SWT.NONE).setText("年龄");
layout.addColumnData(newColumnWeightData(60));
newTableColumn(table,SWT.NONE).setText("记录建立时间");
//第四步:
设置内容器和标签器
tv.setContentProvider(newTableViewerContentProvider());
tv.setLabelProvider(newTableViewerLabelProvider());
//第五步:
用TableViewer的setInput方法将数据输入到表格
Objectdata=PeopleFactory.getPeoples();
tv.setInput(data);
//-------------文件名:
TableViewerContentProvider.java-------------------
//内容器。
由此类对输入到表格的数据进行筛选和转化。
此类要实现接口的3种方法,其中
//getElements是主要方法,另外两个方法很少用到,空实现就行了
publicclassTableViewerContentProviderimplementsIStructuredContentProvider{
//对输入到表格的数据集合进行筛选和转化。
输入的数据集全部要转化成数组,每一个数组元素
//就是一个实体类对象,也就是表格中的一条记录
publicObject[]getElements(Objectelement){
//参数element就是通过setInput(Objectinput)输入的对象input
//本例中输入给setInput是List集合
if(elementinstanceofList)//加一个List类型判断
return((List)element).toArray();//将数据集List转化为数组
else
returnnewObject[0];//如非List类型则返回一个空数组
}
//当TableViewer对象被关闭时触发执行此方法
publicvoiddispose(){}
//当TableViewer再次调用setInput()时触发执行此方法
publicvoidinputChanged(Viewerv,ObjectoldInput,ObjectnewInput){}
}
//-------------文件名:
TableViewerLabelProvider.java-------------------
//标签器。
如果说内容器是对输入表格的数据集作处理,那么标签器则是对数据集中的单个实体对象
//进行处理和转化,由标签器来决定实体对象中的字段显示在表格的哪一列中
publicclassTableViewerLabelProviderimplementsITableLabelProvider{
//创建几个图像
privateImage[]images=newImage[]{
newImage(null,"icons/refresh.gif"),
newImage(null,"icons/star.jpg"),
newImage(null,"icons/moon.jpg")};
//由此方法决定数据记录在表格的每一列显示什么文字。
element参数是一个实体类对象
//col是当前要设置的列的列号,0是第一列
publicStringgetColumnText(Objectelement,intcol){
PeopleEntityo=(PeopleEntity)element;//类型转换
if(col==0)//第一列要显示什么数据
returno.getId().toString();
if(col==1)
returno.getName();
if(col==2)
returno.isSex()?
"男":
"女";
if(col==3)
returnString.valueOf(o.getAge());//将int型转为String型
if(col==4)
returno.getCreateDate().toString();
returnnull;//方法可以返回空值
}
//getColumnText方法用于显示文字,本方法用于显示图片
publicImagegetColumnImage(Objectelement,intcol){
PeopleEntityo=(PeopleEntity)element;
//只让“陈刚”这条记录显示图片
if(o.getName().equals("陈刚")||o.getName().equals("周阅")){
if(col==0)//第一列要显示的图片
returnimages[0];
if(col==2)//根据性别显示不同的图标
returno.isSex()?
images[1]:
images[2];
}
returnnull;//方法可以返回空值
}
//当TableViewer对象被关闭时触发执行此方法
publicvoiddispose(){
//别忘了SWT组件的原则:
自己创建,自释放
for(Imageimage:
images){
image.dispose();
}
}
//-------------以下方法很少使用,先不用管,让它们空实现-----------------
publicbooleanisLabelProperty(Objectelement,Stringproperty){returnfalse;}
publicvoidaddListener(ILabelProviderListenerlistener){}
publicvoidremoveListener(ILabelProviderListenerlistener){}
}
程序说明:
TableViewer的setInput方法的参数类型是Object,所以它可以接受任何类型的参数,因此在内容器中要将参数转换过来,如(List)element。
但如果setInput不是List类型的参数,程序就会出错,所以最好用elementinstanceofList来作一下类型判断会比较稳妥,在SWT/JFace编程中很多BUG都出在这种地方。
当然,本例的setInput参数定的就是List类型,不用instanceof判断直接类型转换也没什么问题。
14.3响应鼠标双击事件
如何让TableViewer的每一行响应鼠标的双击或单击事件呢?
又如何取得被选择中的记录数据呢?
本节将解决这个问题。
本节实例的效果如图14.5所示,双击表格中的某条记录时弹出一个提示框,框中的文字信息显示该记录的人名。
图14.5鼠标响应的效果图
本节实例在14.2节的代码基础上修改完成(完整代码见配书光盘的TableViewer2.java文件),具体如下。
在tv.setInput(data)一句之后,添加一个自定义方法addListener(tv),在此方法中给TableViewer添加监听器。
addListener方法的代码如下:
privatevoidaddListener(TableViewertv){
//鼠标双击事件监听
tv.addDoubleClickListener(newIDoubleClickListener(){
publicvoiddoubleClick(DoubleClickEventevent){
//得到表格的选择对象,里面封装了表格中被选择的记录信息
IStructuredSelectionselection=(IStructuredSelection)event.getSelection();
//得到所选择的第一条实体对象(表格可以有多选),并进行类型转换
PeopleEntityo=(PeopleEntity)selection.getFirstElement();
//弹出一个提示框
MessageDialog.openInformation(null,"提示",o.getName());
}
});
//选择事件(单击)监听
tv.addSelectionChangedListener(newISelectionChangedListener(){
publicvoidselectionChanged(SelectionChangedEventevent){
//事件处理代码……(略)
}
});
}
14.4给表格加上右键菜单(Action类、ActionGroup类、MenuManager类)
本节来给表格加上如图14.6所示的右键菜单。
本节实例在前两节的代码基础上修改完成(完整代码见配书光盘的TableViewer3.java文件)。
图14.6右键菜单的效果图
14.4.1Action、ActionGroup、MenuManager介绍
SWT中菜单是Menu类,本书在前面章节中已经介绍过Menu类的使用,在第11章中菜单项用MenuItem类来实现。
但在实际项目中,同一种功能会有多种表现形式,例如Eclipse中的“新建”功能,它会分别出现在主菜单、主工具栏、右键菜单里。
如果都是用MenuItem来实现,就需要写3份类似的代码,以后也要维护3份代码。
当然也可以将事件处理写成外部类来共享代码,但名称、图像以及一些其他的信息写成外部类来共享则不太方便。
JFace包中已经对以上问题提供了解决方案,JFace提供了一个Action类