JFace中提供了TableViewer组件,用TableViewer来表示表格。TableViewer 和TreeViewer类似,它也提供了内容提供器(IStructuredContentProvider)和标签提供器(ITableLabelProvider),用来组织表格的信息。15.3.1 TableViewer构建步骤

TableViewer中主要通过内容提供器(IStructuredContentProvider)和标签提供器(ITable- LabelProvider)组织表中单元格的显示信息。TableViewer构建步骤如下。

(1)创建TableViewer对象,例如“tableViewer = new TableViewer(table);”,其中table是SWT中Table对象。

(2)设定内容管理器,例如“tableViewer.setContentProvider(contentProvider);”。

(3)设定标签提供器,例如“tableViewer.setLabelProvider(labelProvider);”。

(4)设定TableViewer的输入数据,例如“tableViewer.setInput("root");”(用户可以通过输入数据构建表)。

另外,用户可以添加排序器和过滤器对表格数据进行排序和过滤,后面将通过实例介绍排序器和过滤器。
15.3.2 内容提供器(IStructuredContentProvider)

TableViewer中的内容管理器比较简单,用户可以通过实现getElements返回表格的所有数据。

getElements定义为“public Object[] getElements(Object inputElement)”,返回Object[]对象数组,其中数组中每一个对象代表表格的一列。当TableViewer输入数据后,内容管理器将根据输入数据构造表格对象数据,如下代码所示。

public Object[] getElements(Object inputElement) {

  //通过输入的数据建表

  Vector v = (Vector) inputElement;

  return v.toArray();

}

其中,输入数据inputElement为Vector类型的变量,通过“v.toArray();”返回对象数组。
15.3.3 标签提供器(ITableLabelProvider)

TableViewer中的标签提供器主要负责每个单元格中文本和图标的显示。ITableLabelProvider接口要求实现getColumnText和getColumnImage两个主要的方法,getColumnText返回指定单元格的显示文本,getColumnImage返回指定单元格的显示图标,解释如下。

(1)getColumnText:此函数定义为“public String getColumnText(Object element, int columnIndex)”,其中element表示单元格所在行的对象,columnIndex表示单元格所在的列,返回显示的文本。如下代码返回Bug对象的某特定列的显示文本。

  public String getColumnText(Object element, int columnIndex) {

  Bug bug = (Bug) element;

  switch (columnIndex) {

  case 0:

  return bug.id;

  case 1:

  return bug.summary;

  case 2:

  return bug.assignedTo;

  case 3:

  return bug.isSolved ? "YES" : "NO";

  }

  return null;

  }

(2)getColumnImage:此函数定义为“public Image getColumnImage(Object element, int columnIndex)”,其中element表示单元格所在行的对象,columnIndex表示单元格所在的列,返回此单元格的显示图标。如下代码返回Bug对象的某特定列的显示图标。

  public Image getColumnImage(Object element, int columnIndex) {

  if (columnIndex == 0)

  return bugIcon;

  return null;

  }

从上面代码可以看出,只有第一列显示图标,其他列不显示图标。
15.3.4 TableViewer实例

本节的实例为一个Bug列表实例(BugTrackerTableViewer),程序的功能如下。

(1)在窗口中通过ToolBar建立工具栏,并通过ToolBarManager添加相应的Action到工具栏中。

(2)在表格中设置内容管理器和标签管理器。

(3)在表格的每一列添加排序器。当用户单击列头时,排序器将按列排序。排序器中主要通过compare方法比较两行(即两个对象)中的特定列单元格数据大小,返回比较后表格排列的顺序。

(4)通过工具栏的Action(actionShowUnsolvedOnly)添加或删除过滤器,过滤器将根据过滤条件选择出符合要求的行(即对象)。

另外,程序中将在运行时加载上次存储的Bug列表,用户也可以保存当前的Bug列表,程序如例程15-5所示。

例程15-5 BugTrackerTableViewer.java

  //内部类Bug,代表一个BUG显示

  public static class Bug {

   

  public String id;

  public String summary;

  public String assignedTo;

  public boolean isSolved;

  public Bug(String id, String summary, String assignedTo,

  boolean isSolved) {

  this.id = id;

  this.summary = summary;

  this.assignedTo = assignedTo;

  this.isSolved = isSolved;

  }

  public static Vector loadBugs(File file) {

  Vector v = new Vector();

   

  DataInputStream in = null;

  try {

  if (!file.exists())

  return v;

  in = new DataInputStream(new FileInputStream(file));

  while (true) {

  String id = in.readUTF();

  String summary = in.readUTF();

  String assignedTo = in.readUTF();

  boolean solved = in.readBoolean();

  v.add(new Bug(id, summary, assignedTo, solved));

  }

  } catch (IOException ioe) {

   

  } finally {

  try {

  if (in != null)

  in.close();

  } catch (IOException e) {

  e.printStackTrace();

  }

  }

  return v;

  }

  }

  Display display = new Display();

  Shell shell = new Shell(display);

  Table table;

  TableViewer tableViewer;

  Vector bugs;

  Image bugIcon = new Image(shell.getDisplay(), "icons/java2s.gif");

  String[] colNames = new String[] { "ID", "Summary", "Assigned to", "Solved" };

  //实现表格的排序器

  class BugSorter extends ViewerSorter {

  private String property;

  private int propertyIndex;

  public BugSorter(String sortByProperty) {

  for (int i = 0; i < colNames.length; i++) {

  if (colNames[i].equals(sortByProperty)) {

  this.property = sortByProperty;

  this.propertyIndex = i;

  return;

  }

  }

  throw new IllegalArgumentException("Unrecognized property: "

  + sortByProperty);

  }

   

  //比较e1和e2的大小

  public int compare(Viewer viewer, Object e1, Object e2) {

  Bug bug1 = (Bug) e1;

  Bug bug2 = (Bug) e2;

  switch (propertyIndex) {

  case 0:

  return bug1.id.compareTo(bug2.id);

  case 1:

  return bug1.summary.compareTo(bug2.summary);

  case 2:

  return bug1.assignedTo.compareTo(bug2.assignedTo);

  case 3:

  if (bug1.isSolved == bug2.isSolved)

  return 0;

  if (bug1.isSolved)

  return 1;

  else

  return -1;

  default:

  return 0;

  }

  }

  }

  public BugTrackerTableViewer() {

  // 添加工具栏的相应Action

  //添加新建按钮的Action

  Action actionAddNew = new Action("New bug") {

  public void run() {

  // Append.

  Bug bug = new Bug("", "", "", false);

  bugs.add(bug);

  tableViewer.refresh(false);

  }

  };

  Action actionDelete = new Action("Delete selected") {

  public void run() {

  IStructuredSelection selection = (IStructuredSelection) 
  tableViewer.getSelection();

  Bug bug = (Bug) selection.getFirstElement();

  if (bug == null) {

  System.out.println("Please select an item first. ");

  return;

  }

  MessageBox messageBox = new MessageBox(shell, SWT.YES | SWT.NO);

  messageBox.setText("Confirmation");

  messageBox.setMessage("Are you sure to remove the bug with id #"

  + bug.id);

  if (messageBox.open() == SWT.YES) {

  bugs.remove(bug);

  tableViewer.refresh(false);

  }

  }

  };

  Action actionSave = new Action("Save") {

  public void run() {

  saveBugs(bugs);

  }

  };

  //添加表的过滤器

  final ViewerFilter filter = new ViewerFilter() {

  public boolean select(Viewer viewer, Object parentElement,

  Object element) {

  if (!((Bug) element).isSolved)

  return true;

  return false;

  }

  };

  Action actionShowUnsolvedOnly = new Action("Show unsolved only") {

  public void run() {

  if (!isChecked())

  tableViewer.removeFilter(filter);

  else

  tableViewer.addFilter(filter);

  }

  };

  actionShowUnsolvedOnly.setChecked(false);

  ToolBar toolBar = new ToolBar(shell, SWT.RIGHT | SWT.FLAT);

  ToolBarManager manager = new ToolBarManager(toolBar);

  // 添加工具项,并把工具项关联到相应的Action

  manager.add(actionAddNew);

  manager.add(actionDelete);

  manager.add(new Separator());

  manager.add(actionSave);

  manager.add(new Separator());

  manager.add(actionShowUnsolvedOnly);

  manager.update(true);

  shell.setLayout(new GridLayout());

  table = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION);

  TableColumn tcID = new TableColumn(table, SWT.LEFT);

  tcID.setText(colNames[0]);

  TableColumn tcSummary = new TableColumn(table, SWT.NULL);

  tcSummary.setText(colNames[1]);

  TableColumn tcAssignedTo = new TableColumn(table, SWT.NULL);

  tcAssignedTo.setText(colNames[2]);

  TableColumn tcSolved = new TableColumn(table, SWT.NULL);

  tcSolved.setText(colNames[3]);

  tcID.setWidth(60);

  tcSummary.setWidth(200);

  tcAssignedTo.setWidth(80);

  tcSolved.setWidth(50);

  tableViewer = new TableViewer(table);

  tableViewer.getTable().setLinesVisible(true);

  tableViewer.getTable().setHeaderVisible(true);

  tableViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));

  //设定表的内容管理器

  tableViewer.setContentProvider(new IStructuredContentProvider() {

  //获得所有对象

  public Object[] getElements(Object inputElement) {

  //通过输入的数据建表

  Vector v = (Vector) inputElement;

  return v.toArray();

  }

  public void dispose() {

  System.out.println("Disposing ...");

  }

  public void inputChanged(Viewer viewer, Object oldInput,

  Object newInput) {

  System.out.println("Input changed: old="+oldInput + ", new="

  + newInput);

  }

  });

  //设定表的标签管理器

  tableViewer.setLabelProvider(new ITableLabelProvider() {

  public Image getColumnImage(Object element, int columnIndex) {

  if (columnIndex == 0)

  return bugIcon;

  return null;

  }

  //获得列的显示文本

  public String getColumnText(Object element, int columnIndex) {

  Bug bug = (Bug) element;

  switch (columnIndex) {

  case 0:

  return bug.id;

  case 1:

  return bug.summary;

  case 2:

  return bug.assignedTo;

  case 3:

  return bug.isSolved ? "YES" : "NO";

  }

  return null;

  }

  public void addListener(ILabelProviderListener listener) {

  }

  public void dispose() {

  }

  public boolean isLabelProperty(Object element, String property) {

  return false;

  }

  public void removeListener(ILabelProviderListener listener) {

  }

  });

  //设定单元格编辑器

  tableViewer.setColumnProperties(colNames);

  CellEditor[] cellEditors = new CellEditor[4];

  cellEditors[0] = new TextCellEditor(table);

  cellEditors[1] = cellEditors[0];

  cellEditors[2] = cellEditors[0];

  cellEditors[3] = new CheckboxCellEditor(table);

  tableViewer.setCellEditors(cellEditors);

  //设定单元格修改器

  tableViewer.setCellModifier(new ICellModifier() {

  public boolean canModify(Object element, String property) {

  return true;

  }

  public Object getValue(Object element, String property) {

  .

  int index = -1;

  for (int i = 0; i < colNames.length; i++) {

  if (colNames[i].equals(property)) {

  index = i;

  break;

  }

  }

  Bug bug = (Bug) element;

  switch (index) {

  case 0:

  return bug.id;

  case 1:

  return bug.summary;

  case 2:

  return bug.assignedTo;

  case 3:

  return new Boolean(bug.isSolved);

  }

  return null;

  }

  public void modify(Object element,String property,Object value) {

  System.out.println("Modify: " + element + ", " + property

  + ", " + value);

   

  int index = -1;

  for (int i = 0; i < colNames.length; i++) {

  if (colNames[i].equals(property)) {

  index = i;

  break;

  }

  }

  Bug bug = null;

  if (element instanceof Item) {

  TableItem item = (TableItem) element;

  bug = (Bug) item.getData();

  } else {

  bug = (Bug) element;

  }

  switch (index) {

  case 0:

  bug.id = (String) value;

  break;

  case 1:

  bug.summary = (String) value;

  break;

  case 2:

  bug.assignedTo = (String) value;

  break;

  case 3:

  bug.isSolved = ((Boolean) value).booleanValue();

  break;

  }

  tableViewer.update(bug, null);

  }

  });

  //设定表格的排序方式

  //单击第一列列头按第一列排序

  tcID.addListener(SWT.Selection, new Listener() {

  public void handleEvent(Event event) {

  tableViewer.setSorter(new BugSorter(colNames[0]));

  }

  });

  //单击第二列列头按第二列排序  

  tcSummary.addListener(SWT.Selection, new Listener() {

  public void handleEvent(Event event) {

  tableViewer.setSorter(new BugSorter(colNames[1]));

  }

  });

  //单击第三列列头按第三列排序  

  tcAssignedTo.addListener(SWT.Selection, new Listener() {

  public void handleEvent(Event event) {

  tableViewer.setSorter(new BugSorter(colNames[2]));

  }

  });

  //单击第四列列头按第四列排序  

  tcSolved.addListener(SWT.Selection, new Listener() {

  public void handleEvent(Event event) {

  tableViewer.setSorter(new BugSorter(colNames[3]));

  }

  });

  //从文件中读取Bug记录

  bugs = Bug.loadBugs(new File("bugs.dat"));

  //把bugs作为表格的输入

  tableViewer.setInput(bugs);

  shell.pack();

  shell.open();

   

  while (!shell.isDisposed()) {

  if (!display.readAndDispatch()) {  

  display.sleep();

  }

  }

  display.dispose();

  }

  //保存当前的Bug记录

  private void saveBugs(Vector v) {

   

  DataOutputStream out = null;

  try {

  File file = new File("bugs.dat");

  out = new DataOutputStream(new FileOutputStream(file));

  for (int i = 0; i < v.size(); i++) {

  Bug bug = (Bug) v.elementAt(i);

  out.writeUTF(bug.id);

  out.writeUTF(bug.summary);

  out.writeUTF(bug.assignedTo);

  out.writeBoolean(bug.isSolved);

  }

  } catch (IOException ioe) {

   

  } finally {

  try {

  if (out != null)

  out.close();

  } catch (IOException e) {

  e.printStackTrace();

  }

  }

  }

  public static void main(String[] args) {

  new BugTrackerTableViewer();

  }

}

上例为表格添加了过滤器和排序器,用户可以单击表格的列头按此列进行排序。另外,还能够通过工具栏按钮过滤掉已解决的Bug信息。程序运行效果如图15-3所示。



图15-3 TableViewer组件

TableViewer的功能比较强大,在复杂的应用中可以用它代替SWT中的Table组件,实现表格的完美展现。

除了TreeViewer和TableViewer组件外,JFace中还封装了ListViewer等组件,用户可以直接使用这些组件实现自己的功能。