TableViewer的使用一般有以下步骤:
1. new一个TableViewer对象。在new 的时候通过参数可以定义它的一些属性(如下例),属性英文单词的比较明显示,不再说明。
2. 对其布局(这和其它控件没什么区别)。
主要是tableviewer上table的布局,比较常用的就是以下三个方法:
namespacesTable.setLayoutData(namespaceTableGridData);
namespacesTable.setLinesVisible(true);
namespacesTable.setHeaderVisible(true);
3. 建立表格中的列。
可以通过tableviewer上的table来建立
4. 设定内容器。一般写成内部类,但内容器基本一样,你可以单独拿出来写成一个类,让整个系统共用。
setContentProvider的使用,详细见实例。
5. 设定标签器。这个比较重要和复杂一些。
setContentProvider的使用,详细见实例。
6. 用setInput输入数据。以后这些数据会根据列设置、内容器、标签器的设定将自己显示在TableViewer的表格中。
设置好后,数据是自动输入。
以下是转载的一个例子,说的很详细,而且可能比较常用,所以贴出来,感谢作者陈刚。(桂林人,97年毕业于广西师范大学数学系,专注于Java平台。现(2004.2-?)暂在IBM中国研究中心进行Eclipse插件的开发。)
public class App1 {
public static void main(String[] args) {
App1 window = new App1();
window.open();
}
public void open() {
final Display display = new Display();
final Shell shell = new Shell();
shell.setLayout(new FillLayout());
shell.setText("SWT Application");
{
TableViewer tv = new TableViewer(shell, SWT.MULTI SWT.H_SCROLL SWT.V_SCROLL SWT.BORDER SWT.FULL_SELECTION);
/*
* TableViewer是通过Table来布局的
*/
Table table = tv.getTable();
//table.setLayoutData(new GridData(GridData.FILL_BOTH));
table.setHeaderVisible(true); //表头显示
table.setLinesVisible(true); //表格线显示
/*
* 建立表格中的列
*/
TableLayout tLayout = new TableLayout();
table.setLayout(tLayout);
tLayout.addColumnData(new ColumnWeightData(10)); //10个单位的宽度
new TableColumn(table, SWT.NONE).setText("ID号");
tLayout.addColumnData(new ColumnWeightData(40));
new TableColumn(table, SWT.NONE).setText("姓名");
tLayout.addColumnData(new ColumnWeightData(20));
new TableColumn(table, SWT.NONE).setText("年龄");
tLayout.addColumnData(new ColumnWeightData(60));
new TableColumn(table, SWT.NONE).setText("记录建立时间");
/*
* 当People的记录集输入的tv中,注意setInput的参数是Object也就是说它可以接受任何参数,
* 不过它最常接受的还是Java的Collection(集合,这里为List)或者数组,
* 那么tv是怎么知道如何来显示这么输入格式千差万别的数据的呢?就是依靠内容器和标签器(这里它两是一个内部类)
*/
tv.setContentProvider(new MyContentProvider()); //内容器
tv.setLabelProvider(new MyLabelProvider()); //标签器
tv.setInput(getPeoples());
}
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
}
/**
* PeopleEntity对象的生成工厂,生成三个PeopleEntry对象,并放到一个List中
* 在实现应用中这个方法可改为从数据库中取数据,然后将数据包装成一个个实体类,并将这些实体类装在List集合中返回
* @return
*/
private List getPeoples() {
List peoples = new ArrayList();
{ //第1个
PeopleEntity p = new PeopleEntity();
p.setId(new Long(1));
p.setName("陈刚");
p.setAge(28);
p.setCreateDate(new Date()); //当前日期
peoples.add(p);
}
{ //第2个
PeopleEntity p = new PeopleEntity();
p.setId(new Long(2));
p.setName("韩立新");
p.setAge(29);
p.setCreateDate(new Date());
peoples.add(p);
}
{ //第3个
PeopleEntity p = new PeopleEntity();
p.setId(new Long(3));
p.setName("陈常恩");
p.setAge(27);
p.setCreateDate(new Date());
peoples.add(p);
}
return peoples;
}
/**
* 内容器(写成了一个内部类). 在这里对所有记录集中的记录进行处理
*/
private static final class MyContentProvider implements IStrUCturedContentProvider {
public Object[] getElements(Object element) {
if (element instanceof List)
return ((List) element).toArray();//将List转化为数组
else
return new Object[0];//否则,返回一个空数组
}
public void dispose() {}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
}
/**
* 标签器(写成了一个内部类).在这里对单条记录进行处理
*/
private static final class MyLabelProvider implements ITableLabelProvider {
/**
* 这个方法返回的是各列的记录的文字
* 参数1:输入的对象
* 参数2:列号
* 返回值:注意一定要避免Null值,否则出错
*/
public String getColumnText(Object element, int col) {
PeopleEntity o = (PeopleEntity) element; //转换一下类型
if (col == 0)
return o.getId().toString();
if (col == 1)
return o.getName();
if (col == 2)
return "" + o.getAge();//加个""是为了将int型转为String型
if (col == 3)
return o.getCreateDate().toString();
return "";
}
/**
* 返回每条记录前面的图标
*/
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
//-------------以下方法用处不大,暂时不管它-----------------
public void addListener(ILabelProviderListener listener) {}
public void dispose() {}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void removeListener(ILabelProviderListener listener) {}
}
}
package net.yeah.glchengang.tableviewer;
import Java.util.Date;
/**
* 这是一个实体类,相当于数据库中的一条记录。
* 具体为一个人的记录,象征性的包含四个不同数据类型的字段。
* 这些字段都是private的,然后以其相应的set/get方法来访问
*/
public class PeopleEntity {
private Long id; //唯一识别码,在数据库里为自动递增的ID列
private String name; //姓名
private int age; //年龄
private Date createDate; //记录的建立日期
public Long getId() {
return id;
}
public void setId(Long long1) {
id = long1;
}
public String getName() {
return name;
}
public void setName(String string) {
name = string;
}
public int getAge() {
return age;
}
public void setAge(int i) {
age = i;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date date) {
createDate = date;
}
不过,对于我的需求,可能列数并不需要这么多,然而却提添加了其他的一些功能,例如实现table的单击编辑,添加行和删除行,以及tab键的逐个单元扫描并聚焦。这些问题困扰了我好几天,可能这在有经验的开发人员根本不是问题,不过对于我这种java菜鸟来说可能是必须交的学费吧。
找了很多资料,一开始在网上看见一个可编辑的table示例,拿来一用,确实好使,可编辑的功能很快就实现了。
这个示例只是在table上加一个监听器代码如下:
namespacesTable.addListener(SWT.MouseDown, new Listener() {
public void handleEvent(Event event) {
Rectangle clientArea = namespacesTable.getClientArea();
Point pt = new Point(event.x, event.y);
int index = namespacesTable.getTopIndex();
while (index < namespacesTable.getItemCount()) {
boolean visible = false;
final TableItem item = namespacesTable.getItem(index);
for (int i = 0; i < namespacesTable.getColumnCount(); i++) {
Rectangle rect = item.getBounds(i);
if (rect.contains(pt)) {
final int column = i;
final Text text = new Text(namespacesTable, SWT.NONE);
Listener textListener = new Listener() {
public void handleEvent(final Event e) {
switch (e.type) {
case SWT.FocusOut:
item.setText(column, text.getText());
text.dispose();
break;
case SWT.Traverse:
switch (e.detail) {
case SWT.TRAVERSE_RETURN:
item
.setText(column, text
.getText());
//FALL THROUGH
case SWT.TRAVERSE_ESCAPE:
text.dispose();
e.doit = false;
case SWT.TRAVERSE_TAB_NEXT:
if(column==0){
if (selectedItem != null) {
if (e.detail == SWT.TRAVERSE_RETURN
|| e.detail == SWT.TRAVERSE_TAB_NEXT) {
e.doit = false;
// tableViewer.editElement(selectedItem
// .getData(), 1);
}
}
}
else if(column==1){
int index = namespacesTable.indexOf(selectedItem);
e.doit = true;
if (index == namespacesTable.getItemCount() - 1) {
namespacesTable.setSelection(0);
// tableViewer.editElement(namespacesTable
// .getItem(0).getData(), 0);
selectedItem = namespacesTable.getItem(0);
}
if (namespacesTable.getItemCount() > index + 1
&& namespacesTable.getItem(index + 1) != null) {
namespacesTable.setSelection(namespacesTable
.getItem(index + 1));
// tableViewer.editElement(namespacesTable.getItem(
// index + 1).getData(), 0);
selectedItem = namespacesTable.getItem(index + 1);
}
}
}
break;
}
}
};
text.addListener(SWT.FocusOut, textListener);
text.addListener(SWT.Traverse, textListener);
text.setText(item.getText(i));
text.selectAll();
text.setFocus();
return;
}
if (!visible && rect.intersects(clientArea)) {
visible = true;
}
}
if (!visible)
return;
index++;
}
}
});
有兴趣的朋友可以看下这段代码,其实它是用了一个很巧妙的方法实现了可编辑,但是正因为不规范,给后面的需求实现带来了巨大的困难,贴出来只是让同是java菜鸟的初级开发人员少走我的弯路。代码中还有一些被注释掉的部分,可以看出我对tab实现的尝试和无知。
之后,经过跟有经验的开发人员沟通,我明白了,基于这种可编辑的实现方法进行tab的遍历是极端困难的,因为用于编辑的text是临时创建的,所以要实现遍历只能再次建立,但是脱离了鼠标事件获取建立的坐标是极端困难的,或许根本不可能。
所以,所以,所以,我只能删掉这段代码,重新采用别的方法实现,那就是TextCellEditor。当然,从名字可以看出来,这是一个text,既有editable功能的widget,要实现对它的编辑当然还需要tableviewer。setCellModifier的方法就是为其加一个cell的edit监听事件。其中,实现了ICellModifier的三个方法:canModify,getValue和modify来实现对cell的编辑。详细见后面的例子。
接下来说说tableviewer中table的内容的设置,事实上就是设置内容器,标签器以及setInput输入内容,前辈陈刚已经介绍的很详细,我想我也没有什么可以补充的。不过陈刚的例子只是讲出了读取数据并显示出来,并没有涉及到添加和删除行的操作。经过研究,我终于算是明白了些许:
通过setInput为table添加了一个list后(大多数情况是这样,参照上面的代码),以后只要对这个list里的元素进行添加和删除,table中的数据就会自动添加和删除,当然每次操作后你需要调用refresh方法对tableviewer进行刷新。
另外,对于聚焦的实现,方法很简单,就是在new TextCellEditor时override一下setFocus的方法,当然要摁tab逐一扫描后聚焦,这只是一个逻辑问题,在此不在多说,参见代码。需要补充的一点是需要在每个setFocus方法里设置一个标志,用来防止死循环,例如代码中的prefixFlag和urlFlag。
以下是我写的相关代码,仅供参考:
public class CBESBNamespaceGroup extends Composite {
public Table namespacesTable;
private Button removeButton;
private Button newButton;
private CBESBNamespace cbrNamespace;
protected boolean prefixFlag = false;
protected boolean urlFlag = false;
protected TextCellEditor prefixEditor;
protected TextCellEditor urlEditor;
protected TableItem selectedItem = null;
protected TableViewer tableViewer;
private NamespaceContentProvider namespaceContentProvider=new NamespaceContentProvider();
/**
* @param parent
* @param style
* @param isUpdate
*/
public CBESBNamespaceGroup(Composite parent, int style,final List<CBESBNamespace> namespacesList,boolean isUpdate) {
super(parent, style);
setLayout(new FillLayout());
final Group namespacesGroup = new Group(this, SWT.NONE);
final GridLayout gridLayout = new GridLayout();
gridLayout.marginWidth = 0;
gridLayout.verticalSpacing = 10;
gridLayout.numColumns = 1;
namespacesGroup.setLayout(gridLayout);
namespacesGroup.setText("Namespace");
//TODO:I18n
final Composite composite = new Composite(namespacesGroup, SWT.NONE);
final GridLayout gridLayout_1 = new GridLayout();
gridLayout_1.marginWidth = 0;
gridLayout_1.marginHeight = 0;
gridLayout_1.numColumns = 2;
composite.setLayout(gridLayout_1);
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true,
false, 1, 3);
gridData.heightHint = 90;
composite.setLayoutData(gridData);
tableViewer = new TableViewer(composite, SWT.MULTI
| SWT.FULL_SELECTION | SWT.BORDER);
tableViewer.getControl().setLayoutData(new GridLayout());
tableViewer.setColumnProperties(new String[] {"Prefix","URL"});
tableViewer.setContentProvider(namespaceContentProvider);
tableViewer.setLabelProvider(new NamespaceLabelProvider());
tableViewer.setInput(namespacesList);
namespacesTable=tableViewer.getTable();
namespacesTable.addSelectionListener(new SelectionAdapter(){
public void widgetSelected(SelectionEvent e) {
selectedItem = (TableItem) e.item;
}});
initTableEditors();
final GridData namespaceTableGridData = new GridData(SWT.FILL, SWT.CENTER, true,
true, 1, 3);
namespaceTableGridData.heightHint = 100;
namespaceTableGridData.widthHint = 320;
namespacesTable.setLayoutData(namespaceTableGridData);
namespacesTable.setLinesVisible(true);
namespacesTable.setHeaderVisible(true);
final TableColumn replyLanguageColumn = new TableColumn(namespacesTable,
SWT.NONE);
replyLanguageColumn.setWidth(60);
replyLanguageColumn.setText("Prefix");
final TableColumn replyClassTableColumn = new TableColumn(namespacesTable,
SWT.NONE);
replyClassTableColumn.setWidth(230);
replyClassTableColumn.setText("URL");
newButton=new Button(composite,SWT.NONE);
// editButton=new Button(composite,SWT.NONE);
removeButton=new Button(composite,SWT.NONE);
newButton.setText("New");
// editButton.setText("Edit");
removeButton.setText("Remove");
newButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
// editButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
removeButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
newButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
cbrNamespace=new CBESBNamespace("ns","http://");
int index=namespacesTable.getItemCount();
if(namespacesTable.getSelectionCount()>0)
index=namespacesTable.getSelectionIndex()+1;
namespacesList.add(index, cbrNamespace);
tableViewer.refresh();
TableItem newItem=namespacesTable.getItem(index);
// newItem.setData(cbrNamespace);
namespacesTable.setSelection(newItem);
// isAltPressed = true;
tableViewer.editElement(newItem
.getData(), 0);
// isAltPressed = false;
selectedItem=newItem;
}
});
removeButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (namespacesTable.getSelection() == null || namespacesTable.getSelection().length == 0)
return;
namespacesList.remove( namespacesTable.getSelectionIndex());
TableItem[] items = namespacesTable.getSelection();
for(TableItem item : items){
item.dispose();
}
namespacesTable.layout();
}
});
tableViewer.refresh();
}
protected void initTableEditors() {
prefixEditor = new TextCellEditor(tableViewer.getTable()) {
@Override
public void setFocus() {
super.setFocus();
if (!prefixFlag)
{
super.text.addTraverseListener(new TraverseListener() {
public void keyTraversed(TraverseEvent e) {
if (selectedItem != null) {
if (e.detail == SWT.TRAVERSE_RETURN
|| e.detail == SWT.TRAVERSE_TAB_NEXT) {
e.doit = false;
tableViewer.editElement(selectedItem
.getData(), 1);
}
}
}
});
}
prefixFlag=true;
}
};
urlEditor = new TextCellEditor(tableViewer.getTable()) {
@Override
public void setFocus() {
super.setFocus();
if (!urlFlag)
{
super.text.addTraverseListener(new TraverseListener() {
public void keyTraversed(TraverseEvent e) {
if (selectedItem != null) {
Table table = tableViewer.getTable();
int index = table.indexOf(selectedItem);
if (e.detail == SWT.TRAVERSE_RETURN) {
e.doit = false;
if (index == table.getItemCount() - 1) {
selectedItem = table.getItem(index + 1);
}
} else if (e.detail == SWT.TRAVERSE_TAB_NEXT) {
e.doit = true;
if (index == table.getItemCount() - 1) {
table.setSelection(0);
tableViewer.editElement(table
.getItem(0).getData(), 0);
selectedItem = table.getItem(0);
}
if (table.getItemCount() > index + 1
&& table.getItem(index + 1) != null) {
table.setSelection(table
.getItem(index + 1));
tableViewer.editElement(table.getItem(
index + 1).getData(), 0);
selectedItem = table.getItem(index + 1);
}
}
}
}
});
}
urlFlag=true;
}
};
// Validators to verify user input in the table cell editors
urlEditor.setValidator(new ICellEditorValidator() {
public String isValid(Object value) {
return null;
}
});
tableViewer.setCellEditors(new CellEditor[] { prefixEditor, urlEditor });
tableViewer.setCellModifier(new ICellModifier(){
public boolean canModify(Object element, String property) {
return true;
}
public Object getValue(Object element, String property) {
if (property == "Prefix") {
if (element instanceof CBESBNamespace)
return ((CBESBNamespace) element).getPrefix();
}
if (property == "URL") {
if (element instanceof CBESBNamespace)
return ((CBESBNamespace) element).getUrl();
}
return null;
}
public void modify(Object item, String property, Object value) {
// Null indicates that the validator rejected the value.
if (value == null)
return;
Object element = item;
if (element instanceof TableItem)
element = ((TableItem) element).getData();
String text = ((String) value).trim();
if (property == "Prefix") {
if (element instanceof CBESBNamespace)
((CBESBNamespace) element).setPrefix(text);
}
if (property == "URL") {
if (element instanceof CBESBNamespace)
((CBESBNamespace) element).setUrl(text);
}
tableViewer.refresh();
}});
// Listener to track the state of the ALT key
tableViewer.getTable().addTraverseListener(new TraverseListener() {
public void keyTraversed(TraverseEvent e) {
if (selectedItem != null) {
Table table = tableViewer.getTable();
int index = table.indexOf(selectedItem);
if (e.detail == SWT.TRAVERSE_TAB_NEXT) {
tableViewer.editElement(selectedItem.getData(), 0);
} else if (e.detail == SWT.TRAVERSE_RETURN) {
if (table.getItemCount() > index + 1
&& table.getItem(index + 1) != null) {
table.setSelection(table.getItem(index + 1));
tableViewer.editElement(table.getItem(index + 1)
.getData(), 0);
selectedItem = table.getItem(index + 1);
} else {
selectedItem = table.getItem(index + 1);
}
}
}
}
});
tableViewer.getTable().addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
if (e.keyCode == SWT.ALT){
e.doit = false;
}
if (e.keyCode == SWT.DEL){
e.doit = false;
}
}
public void keyReleased(KeyEvent e) {
}
});
tableViewer.getTable().addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// isAltPressed = true;
selectedItem = (TableItem) e.item;
}
});
}
public void dialogChange() {
}
@Override
public void dispose() {
super.dispose();
}
@Override
protected void checkSubclass() {
// Disable the check that prevents subclassing of SWT components
}
protected Table getScheduleTable()
{
return namespacesTable;
}
}
public class CBESBNamespace {
private String prefix;
private String url;
public CBESBNamespace() {
super();
}
public CBESBNamespace(String prefix, String url) {
super();
this.prefix = prefix;
this.url = url;
}
/**
* @return the prefix
*/
public String getPrefix() {
return prefix;
}
/**
* @param prefix the prefix to set
*/
public void setPrefix(String prefix) {
this.prefix = prefix;
}
/**
* @return the url
*/
public String getUrl() {
return url;
}
/**
* @param url the url to set
*/
public void setUrl(String url) {
this.url = url;
}
}
public class NamespaceContentProvider implements IStructuredContentProvider {
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
*/
public Object[] getElements(Object inputElement) {
if (inputElement instanceof List)
return ((List) inputElement).toArray();//将List转化为数组
else
return new Object[0];//否则,返回一个空数组
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
public void dispose() {
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
public class NamespaceLabelProvider implements ITableLabelProvider {
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
*/
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
*/
public String getColumnText(Object element, int columnIndex) {
if(element instanceof CBESBNamespace){
CBESBNamespace entry = (CBESBNamespace) element;
switch (columnIndex) {
case 0:
return entry.getPrefix();
case 1:
return entry.getUrl();
}
}
if (element == null)
return "<null>";
return element.toString();
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
*/
public void addListener(ILabelProviderListener listener) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
*/
public void dispose() {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String)
*/
public boolean isLabelProperty(Object element, String property) {
// TODO Auto-generated method stub
return false;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
*/
public void removeListener(ILabelProviderListener listener) {
// TODO Auto-generated method stub
}
}
运行示意图参见图片:
这是我作为一个初级java开发人员写的第一篇博客,因为感觉确实有很多东西需要总结和记录,以便自己以后需要,也能为别人提供便利,所以开通了此博客,写的不好的地方,希望各位前辈多多指点。