Eclipse开发TableViewer

组件TableViewer+CheckBoxTableViewer

CheckBoxTableViewer继承了TableViewer,二者以下简称viewer/查看器,看起来就是表格。

1. 基本使用

类似MVC模式。M即下文说的数据模型,是一个集合,比如DataStore;C可以认为是内容提供器,把数据模型以对象数组形式返回;V可以认为是标签提供器和显示用的组件,标签提供器需要把数据模型解析到viewer中的一个个单元格,集合内的每个元素都是一个对象,表格中的每一列对应对象的一个属性,对于DataObject则需要按照key返回对应的value。

Eclipse开发TableViewer

  1. 创建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);
    
  2. 从Table获取Viewer对象

    //创建CheckboxTableViewer
    final CheckboxTableViewer tableViewer = new CheckboxTableViewer(table);
    
  3. 为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);
    }
    
  4. 设置内容提供器

    //设置内容提供器
    tableViewer.setContentProvider(new ContentProvider());
    
  5. 设置标签提供器

    //设置标签提供器
    tableViewer.setLabelProvider(new TableLabelProvider());
    
  6. 把数据集合(数据模型)交给Viewer

    //把数据集合给tableView
    tableViewer.setInput(dataStore);
    

注释:

  1. 内容提供器

    实现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) {
    	}
    }
    
  2. 标签提供器

    实现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

  1. 通过Viewer的get方法获取该元素(也就是表中的一行),修改该元素属性。
  2. 调用Viewer的refresh()方法刷新表格。

方式2

  1. 直接修改数据模型,包括增删改。

  2. 调用Viewer的refresh()方法刷新表格。

方式3(目前不清楚)

  1. 给数据模型添加增删改的监听器。

  2. 修改模型中的元素后会自动刷新Viewer。

TableViewer和数据模型(本例中的是DataStore对象)中都能够增加删除一条记录,区别在于Viewer中的方法只是在对显示界面的数据进行操作,并未改变数据模型中的数据;而直接在数据模型中增删数据需要调用Viewer的refresh()方法才能显示出增删的数据。

3.行内容可编辑

  1. 自定义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);
        }
    }
    
  2. 为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

  1. 自定义Sorter,继承ViewerSorter,实现compare()方法。

  2. 为每一列添加selecte监听器,之后每次点击该列的表头都会按照该列排序。此方式相对繁琐。

6.筛选/过滤

  1. 自定义过滤器类,继承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;
        }
    }
    
  2. 添加/移除过滤器

    //添加过滤器,添加即生效
    MyFilter myFilter=new MyFilter();
    tableViewer.addFilter(myFilter);
    //移除过滤器,移除即失效
    tableViewer.removeFilter(myFilter);
    

7.DS填充

7.1. DS填进表格

? DS继承了ArrayList,也是数据集合,所以可以直接把它交给tableView,具体显示则需要设计内容提供器和标签提供器。

  1. 如何根据查询结果显示列名?

    获得DS之前无从得知每一列的名字。可通过DS获取列名返回一个数组,在表初始化设计列名时可以利用该数组生成列名。

  2. 提升标签提供器的解析能力:需要设计根据columnIndex返回对应的字符串。详情见基本使用注释部分中标签提供器的getColumnText()方法,该方法对一个DS进行了解析。

7.2. 表格填进DS

  1. 方法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. 方法2:直接获取数据模型。

    DataStore dataStore= (DataStore) tableViewer.getInput();
    

8.右键菜单

  1. 生成Menu对象

    Menu menu = new Menu(shell,SWT.POP_UP);
    
  2. 添加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升序");
    
  3. 为viewer添加右键菜单

    table.setMenu(menu);
    

9.全选/反全选

方式1

? 直接使用CheckBoxTableViewer,利用其自带的selectionAll等相关方法。

方式2

? 添加快捷键(还没学)

10.鼠标拖选选中多行

需要学习鼠标事件。效果如下图。

Eclipse开发TableViewer

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

? https://blog.csdn.net/zengjz888/article/details/84215227

Eclipse开发TableViewer

上一篇:Shell - find files whose name does not contain a pattern


下一篇:Kubernetes-网络