组件TableViewer+CheckBoxTableViewer
CheckBoxTableViewer
继承了TableViewer
,二者以下简称viewer/查看器,看起来就是表格。
1. 基本使用
类似MVC模式。M即下文说的数据模型,是一个集合,比如
DataStore
;C可以认为是内容提供器,把数据模型以对象数组形式返回;V可以认为是标签提供器和显示用的组件,标签提供器需要把数据模型解析到viewer中的一个个单元格,集合内的每个元素都是一个对象,表格中的每一列对应对象的一个属性,对于DataObject
则需要按照key返回对应的value。
-
创建Table
//创建table Table table = new Table(shell, SWT.CHECK|SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER|SWT.V_SCROLL|SWT.H_SCROLL); table.setLayoutData(new GridData(GridData.FILL_BOTH)); table.setLinesVisible(true); table.setHeaderVisible(true); table.setBounds(97, 79, 373, 154);
-
从Table获取Viewer对象
//创建CheckboxTableViewer final CheckboxTableViewer tableViewer = new CheckboxTableViewer(table);
-
为Table设计列名/表头
//准备数据模型DataStore DataStore dataStore= DataStore.getInstance(); dataStore.put(0,"id",147); dataStore.put(0,"name","NYF"); dataStore.put(0,"sex","男"); dataStore.put(0,"age",20); dataStore.put(0,"createDate",new Date()); dataStore.put(1,"id",247); dataStore.put(1,"name","Nnn"); dataStore.put(1,"sex","男"); dataStore.put(1,"age",20); dataStore.put(1,"createDate",new Date()); //通过dataStore获取列名 String[] tableCols = dataStore.getColumnName(); //设计列 for(String colStr : tableCols) { TableColumn tc = new TableColumn(table, SWT.LEFT); //靠左 tc.setText(colStr); tc.setWidth(70); }
-
设置内容提供器
//设置内容提供器 tableViewer.setContentProvider(new ContentProvider());
-
设置标签提供器
//设置标签提供器 tableViewer.setLabelProvider(new TableLabelProvider());
-
把数据集合(数据模型)交给Viewer
//把数据集合给tableView tableViewer.setInput(dataStore);
注释:
-
内容提供器
实现
IStructuredContentProvider
接口,getElements()
方法会把元素集合以数组的形式返回给Viewer。import com.dareway.framework.util.DataStore; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.Viewer; import java.util.List; public class ContentProvider implements IStructuredContentProvider { public Object[] getElements(Object inputElement) { if (inputElement instanceof DataStore) { return ((DataStore) inputElement).toArray(); } else { return new Object[0]; } } public void dispose() { } public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } }
-
标签提供器
实现
ITableLabelProvider
接口,拿到元素集合后,Viewer利用标签提供器将每个元素翻译成对应的单元格(文字或图片)。日常使用表格基本都是文字,所以主要重写getColumnText()
方法。在这个方法中根据columnIndex返回一个String填充到viewer的一个单元格中。import com.dareway.framework.exception.AppException; import com.dareway.framework.util.DataObject; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.swt.graphics.Image; import java.text.SimpleDateFormat; public class TableLabelProvider implements ITableLabelProvider { @Override public Image getColumnImage(Object arg0, int arg1) { return null; } @Override public String getColumnText(Object element, int columnIndex) { if (element instanceof DataObject) { DataObject dataObject=(DataObject) element; //columnNames和columnTypes是可以对应的 //Object[] columnNames = dataObject.keySet().toArray(); //String[] columnTypes=dataObject.getValueTypes(); if (columnIndex == 0) { try { return String.valueOf(dataObject.getInt("id")); } catch (AppException e) { e.printStackTrace(); } } else if (columnIndex == 1) { try { return dataObject.getString("name"); } catch (AppException e) { e.printStackTrace(); } } else if (columnIndex == 2) { try { return dataObject.getString("sex"); } catch (AppException e) { e.printStackTrace(); } } else if (columnIndex == 3) { try { return String.valueOf(dataObject.getInt("age")); } catch (AppException e) { e.printStackTrace(); } } else if (columnIndex == 4) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); try { return sdf.format(dataObject.getDate("createDate")); } catch (AppException e) { e.printStackTrace(); } } } return null; } @Override public void addListener(ILabelProviderListener iLabelProviderListener) { } @Override public void dispose() { } @Override public boolean isLabelProperty(Object o, String s) { return false; } @Override public void removeListener(ILabelProviderListener iLabelProviderListener) { } }
2. 数据刷新
? 数据模型赋给viewer之后,有以下方法可更新表格的显示内容。
方式1
- 通过Viewer的get方法获取该元素(也就是表中的一行),修改该元素属性。
- 调用Viewer的
refresh()
方法刷新表格。
方式2
-
直接修改数据模型,包括增删改。
-
调用Viewer的
refresh()
方法刷新表格。
方式3(目前不清楚)
-
给数据模型添加增删改的监听器。
-
修改模型中的元素后会自动刷新Viewer。
TableViewer和数据模型(本例中的是DataStore对象)中都能够增加删除一条记录,区别在于Viewer中的方法只是在对显示界面的数据进行操作,并未改变数据模型中的数据;而直接在数据模型中增删数据需要调用Viewer的
refresh()
方法才能显示出增删的数据。
3.行内容可编辑
-
自定义CellModifier类,实现ICellModifier接口。
canModify()
方法直接返回true。getValue()
方法不可为空,必须编写,否则抛异常,因为要获取每个单元格该显示的值。鼠标点击该单元格,此时调用一次显示旧数据,随后进入编辑状态,编辑完毕后鼠标离开该单元格,该方法再次调用以显示新数据。在每次编辑完新的值之后,会进入
modify()
方法为单元格设定新编辑的值,在该方法最后一定要调用update()
方法,否则光标离开时显示的还是旧数据。注:编辑表格之后会同时修改数据模型。
import com.dareway.framework.exception.AppException; import com.dareway.framework.util.DataObject; import org.eclipse.jface.viewers.ICellModifier; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.widgets.TableItem; public class MyCellModifier implements ICellModifier { private TableViewer tv; public MyCellModifier(TableViewer tv) { this.tv = tv; } @Override public boolean canModify(Object o, String s) { return true; } @Override public Object getValue(Object element, String property) { DataObject dataObject = (DataObject) element; if (property.equals("name")) { try { return dataObject.getString("name"); } catch (AppException e) { e.printStackTrace(); } } else if (property.equals("sex")) { try { return dataObject.getString("sex"); } catch (AppException e) { e.printStackTrace(); } } else if (property.equals("age")) { try { return String.valueOf(dataObject.getInt("age")); } catch (AppException e) { e.printStackTrace(); } } throw new RuntimeException("error column name : " + property); } @Override public void modify(Object element, String property, Object value) { TableItem item=(TableItem)element; DataObject dataObject=(DataObject)item.getData(); if(property.equals("name")){ String newName = (String)value; if(newName.equals("")){ return ; } try { dataObject.put("name",newName); } catch (AppException e) { e.printStackTrace(); } }else if (property.equals("sex")){ String newSex = (String)value; if(newSex.equals("")){ return ; } try { dataObject.put("sex",newSex); } catch (AppException e) { e.printStackTrace(); } }else if(property.equals("age")){ String newValue = (String)value; if(newValue.equals("")){ return ; } Integer newAge = new Integer(newValue); try { dataObject.put("age",newAge); } catch (AppException e) { e.printStackTrace(); } } tv.update(dataObject, null); } }
-
为Viewer设置Modifier
//设置编辑器 tableViewer.setColumnProperties(tableCols); CellEditor[] cellEditor = new CellEditor[5]; cellEditor[0] = null;//不编辑 cellEditor[1] = new TextCellEditor(tableViewer.getTable());//以下三个可手动编辑 cellEditor[2] = new TextCellEditor(tableViewer.getTable()); cellEditor[3] = new TextCellEditor(tableViewer.getTable()); cellEditor[4] = null;//日期暂时不编辑 tableViewer.setCellEditors(cellEditor); ICellModifier modifier = new MyCellModifier(tableViewer); tableViewer.setCellModifier(modifier);
注释:日期类型组件暂时需要进一步定制
4. 新行增加与所选中的行删除
增加与删除目前计划方案是:
添加按钮,为该按钮添加监听器,触发该监听器之后,在表格上编辑新行或者在数据模型上增减数据,然后刷新viewer。(操作和贡献好像比单纯的监听器更好用?)
addDropSupport目前用法不明
5. 排序
方式1
? 直接按照排序标准给数据模型排序,然后刷新viewer,如果DS的排序够用,这种方法可能方便。
方式2
-
自定义Sorter,继承
ViewerSorter
,实现compare()
方法。 -
为每一列添加selecte监听器,之后每次点击该列的表头都会按照该列排序。此方式相对繁琐。
6.筛选/过滤
-
自定义过滤器类,继承
ViewerFilter
,实现select()
方法,在该方法中定义自己的过滤标准。import com.dareway.framework.exception.AppException; import com.dareway.framework.util.DataObject; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; public class MyFilter extends ViewerFilter { @Override public boolean select(Viewer viewer, Object parentElement, Object element) { DataObject dataObject = (DataObject) element; boolean result=false; try { result=dataObject.getString("name").startsWith("Nn"); } catch (AppException e) { e.printStackTrace(); } return result; } }
-
添加/移除过滤器
//添加过滤器,添加即生效 MyFilter myFilter=new MyFilter(); tableViewer.addFilter(myFilter); //移除过滤器,移除即失效 tableViewer.removeFilter(myFilter);
7.DS填充
7.1. DS填进表格
? DS继承了ArrayList
,也是数据集合,所以可以直接把它交给tableView,具体显示则需要设计内容提供器和标签提供器。
-
如何根据查询结果显示列名?
获得DS之前无从得知每一列的名字。可通过DS获取列名返回一个数组,在表初始化设计列名时可以利用该数组生成列名。
-
提升标签提供器的解析能力:需要设计根据columnIndex返回对应的字符串。详情见基本使用的注释部分中标签提供器的
getColumnText()
方法,该方法对一个DS进行了解析。
7.2. 表格填进DS
-
方法1:先获取viewer的元素,一个元素就是一行,也就是一个
DataObject
,再调用DS的addRow()
方法。DataStore getDS=DataStore.getInstance(); int rows=table.getItemCount(); for (int i = 0; i < rows; i++) { getDS.addRow((DataObject) tableViewer.getElementAt(i)); }
-
方法2:直接获取数据模型。
DataStore dataStore= (DataStore) tableViewer.getInput();
8.右键菜单
-
生成
Menu
对象Menu menu = new Menu(shell,SWT.POP_UP);
-
添加
MenuItem
,并为该项设置属性以及监听器。MenuItem ascMenuItem=new MenuItem(menu,SWT.PUSH); ascMenuItem.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent selectionEvent) { try { dataStore.sort("age"); tableViewer.refresh(); } catch (AppException e) { e.printStackTrace(); } } @Override public void widgetDefaultSelected(SelectionEvent selectionEvent) { } }); ascMenuItem.setText("age升序");
-
为viewer添加右键菜单
table.setMenu(menu);
9.全选/反全选
方式1
? 直接使用CheckBoxTableViewer,利用其自带的selectionAll等相关方法。
方式2
? 添加快捷键(还没学)
10.鼠标拖选选中多行
需要学习鼠标事件。效果如下图。
11.分页
备用参考链接
CellEditor: https://www.cnblogs.com/wayne_wang/archive/2010/01/25/1655742.html
Viewer: https://www.cnblogs.com/xing901022/p/4104409.html
? http://www.blogjava.net/dreamstone/category/24602.html?Show=All
日期时间: https://www.cnblogs.com/huqingyu/archive/2008/04/16/1156428.html