打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
JAVA.SWT/JFace: JFace篇之MVC的表格、树和列表(1)
JAVA.SWT/JFace: JFace篇之MVC的表格、树和列表(1)
2010年08月12日 星期四 10:52

《Eclipse SWT/JFACE 核心应用》 清华大学出版社 19 MVC的表格、树和列表

19.1 MVC概述
    MVC是模型-视图=控制器(Model-View-Controller)设计模式的简称。MVC模式将数据与视图分开,通过控制器来控制与数据交互。JFace中有关实现MVC模式的控件都在org.eclipse.jface.viewers包下。所有的MVC控件都继承自View类,该类是一个抽象类,不能直接创建对象,需使用其实现的子类。常用的类如下:
◆ ListViewer类:列表控件。
◆ TreeViewer类:树控件。
◆ TableViewer类:表格控件。
◆ TextViewer、SourceViewer、ProjectionViewer为编辑文本的控件。

19.2 表格(TableViewer)
表格程序的代码:
package www.swt.com.ch19;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TableColumn;

import www.swt.com.util.ImageFactory;

public class TableWindow extends ApplicationWindow {

private TableViewer table;//声明一个表格对象
private List<PersonEO> persons ;//表格所存储的数据
//表格中列的索引号
public static final int ID = 0;
public static final int NAME = 1;
public static final int GENDER = 2;
public static final int COLOR = 3;
//表格个的列名称
public static final String[] COLUMN_NAME = { "ID号" ,"姓名","性别","喜欢颜色"};
public TableWindow() {
   super(null);
   initPersons();
}

//初始化表格数据,通常是从数据库中读出
private void initPersons() {
   persons = new ArrayList<PersonEO>();
   persons.add( new PersonEO(1,"张三","男","灰色"));
   persons.add( new PersonEO(2,"李四","女","白色"));
}
//设置窗口的标题和大小
protected void configureShell(Shell shell) {
   super.configureShell(shell);
   shell.setSize(300, 200);
   shell.setText("TableViewer程序示例");
}
//创建窗口的控件
protected Control createContents(Composite parent) {
   //创建TableViewer对象
   table = new TableViewer(parent ,SWT.FULL_SELECTION);
   //table = CheckboxTableViewer.newCheckList( parent , SWT.FULL_SELECTION);
   //创建表头
   for ( int i =0; i<COLUMN_NAME.length;i++){
    new TableColumn(table.getTable(), SWT.LEFT).setText(COLUMN_NAME[i]);
    table.getTable().getColumn(i).pack();
   }
  
   //设置排序器
   table.setSorter( new TableSorter());
   //分别为表头的每一列注册事件
   TableColumn column = table.getTable().getColumn(0);
   column.addSelectionListener( new SelectionAdapter(){
    public void widgetSelected(SelectionEvent e) {
     //单击时,重新设置排序对象属性
     ((TableSorter)table.getSorter()).doSort(TableWindow.ID);
     //刷新表格数据
     table.refresh();
    }
   });
   column = table.getTable().getColumn(1);
   column.addSelectionListener( new SelectionAdapter(){
    public void widgetSelected(SelectionEvent e) {
     ((TableSorter)table.getSorter()).doSort(TableWindow.NAME);
     table.refresh();
    }
   });
   column = table.getTable().getColumn(2);
   column.addSelectionListener( new SelectionAdapter(){
    public void widgetSelected(SelectionEvent e) {
     ((TableSorter)table.getSorter()).doSort(TableWindow.GENDER);
     table.refresh();
    }
   });
   column = table.getTable().getColumn(3);
   column.addSelectionListener( new SelectionAdapter(){
    public void widgetSelected(SelectionEvent e) {
     ((TableSorter)table.getSorter()).doSort(TableWindow.COLOR);
     table.refresh();
    }
   });
   //设置表头和表格线可见
     table.getTable().setHeaderVisible(true);
     table.getTable().setLinesVisible( true );
     //设置数据
   table.setContentProvider(new MyContentProvider());
   //设置视图
   table.setLabelProvider( new MyLabelProvider());
   //设置表格数据对象,该方法非常重要,是表格数据入口
   table.setInput(persons);
   createContextMenu();
   //设置列属性
   table.setColumnProperties( COLUMN_NAME );

   //设置单元格编辑器对象数组
     CellEditor[] editors = new CellEditor[4];
     editors[0] = null;
     editors[1] = new TextCellEditor(table.getTable());
     editors[2] = new TextCellEditor(table.getTable());
     editors[3] = new TextCellEditor(table.getTable());
     //设置单元格编辑器
     table.setCellEditors(editors);
   //设置单元个修改器
   table.setCellModifier( new ICellModifier(){
   
    //如果该列为第一列,设置不能修改
    public boolean canModify(Object element, String property) {
     if ( property.equals(COLUMN_NAME[0]))
      return false;
     return true;
    }
    //当处于编辑状态时所显示的值
    public Object getValue(Object element, String property) {
     PersonEO p = (PersonEO) element;
     if ( property.equals(COLUMN_NAME[1]))
      return p.getName();
     else if ( property.equals(COLUMN_NAME[2]))
      return p.getGender();
     else if ( property.equals(COLUMN_NAME[3]))
      return p.getColor();
     return null;
    }
    //当修改后设置更新数据
    public void modify(Object element, String property, Object value) {
     if (element instanceof Item)
      element = ((Item) element).getData();
     PersonEO p = (PersonEO) element;
     if ( property.equals(COLUMN_NAME[1]))
      p.setName( (String)value );
     else if ( property.equals(COLUMN_NAME[2]))
      p.setGender( (String)value );
     else if ( property.equals(COLUMN_NAME[3]))
      p.setColor( (String)value );
     //刷新表格
     table.refresh();
    }
   
   });

   table.addDoubleClickListener( new IDoubleClickListener(){
    public void doubleClick(DoubleClickEvent event) {
     StructuredSelection select = (StructuredSelection) event.getSelection();
     PersonEO p = (PersonEO) select.getFirstElement();
     System.out.println(p.getName());
    }
   
   } );
   return parent;
}

//创建上下文菜单
private void createContextMenu() {
   MenuManager menu = new MenuManager();
   menu.add( new AddAction() );
   menu.add( new DelAction() );
   //menu.add( new FileterAction() );
   //获得一个Menu对象
   Menu m = menu.createContextMenu(getShell());
   //将该对象设置为表格的菜单
   table.getTable().setMenu( m );
}

public static void main(String[] args) {
   TableWindow test = new TableWindow();
   test.setBlockOnOpen(true);
   test.open();
   Display.getCurrent().dispose();

}
public class MyContentProvider implements IStructuredContentProvider {

   //将初始化数据的入口对象转换成表格使用的数组对象
   public Object[] getElements(Object inputElement) {
    if ( inputElement instanceof List )
     return ((List) inputElement).toArray();
    return null;
   }
   //释放该对象时调用的方法
   public void dispose() {

   }
   //当表格中的数据改变时调用该方法
   public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {

   }

}

public class MyLabelProvider implements ITableLabelProvider {
  
   //设置每个单元格所显示的图标
   public Image getColumnImage(Object element, int columnIndex) {
    /*
    //如果是性别所在的列
    if (columnIndex == GENDER){
     //类型转换,element代表表格中的一行
     PersonEO person = (PersonEO)element;
     //根据不同的值设置不同的图标
     if ( person.getGender().equals("男"))
      return ImageFactory.loadImage( Display.getCurrent(),ImageFactory.ICON_BOY);
     else if ( person.getGender().equals("女"))
      return ImageFactory.loadImage( Display.getCurrent(),ImageFactory.ICON_GIRL);
    }
    */
    return null;
   }
   //设置每个单元格所显示的文字
   public String getColumnText(Object element, int columnIndex) {
    //类型转换,element代表表格中的一行
    PersonEO person = (PersonEO)element;
    if ( columnIndex == ID)//如果是第一列 
     return person.getID()+"";
    else if ( columnIndex == NAME)//如果是第二列 
     return person.getName()+"";
    else if ( columnIndex == GENDER)//如果是第三列 
     return person.getGender();
    else if ( columnIndex == COLOR)//如果是第四列 
     return person.getColor()+"";
    return "";
   }
   //释放对象时释放图像资源
   public void dispose() {
    ImageFactory.dispose();
   }
   //以下方法为空实现
   public void addListener(ILabelProviderListener listener) {

   }

   public boolean isLabelProperty(Object element, String property) {
    return false;
   }

   public void removeListener(ILabelProviderListener listener) {

   }

}
public class AddAction extends Action{
   public AddAction(){
    setText("添加");
   }

   public void run() {
    //新建一个实体对象
    PersonEO person = new PersonEO();
    person.setID( table.getTable().getItemCount()+1);
    person.setName("Janet");
    person.setGender("女");
    person.setColor("红色");
    //添加一行数据
    table.add( person );
    persons.add(person); // smx:如果没有这行代码,在点击表头排序时新添加的记录会丢失
   }
  
}
public class DelAction extends Action{
   public DelAction(){
    setText("删除");
   }

   public void run() {
    //获得当前的所选中的行
    StructuredSelection selection = (StructuredSelection) table.getSelection();
    //注意,同时选中的可能是多行,这是返回的是数组对象
    //获得数组对象的一个元素,也就是只有选中一行的情况
    PersonEO p= (PersonEO)selection.getFirstElement();
    //从表中删除该行
    table.remove(p);
   }
  
}
public class FileterAction extends Action{
   //声明一个ViewerFilter对象
   ViewerFilter femaleFilter;
   public FileterAction(){
    //设置标题,样式为复选框样式
    super("筛选",AS_CHECK_BOX);
    //内部类创建该对象
    femaleFilter = new ViewerFilter(){
     //需实现ViewerFilter类中的抽象方法
     public boolean select(Viewer viewer, Object parentElement, Object element) {
      PersonEO p = (PersonEO)element;
      return p.getGender().equals("女");
     }  
    };
    //初始化时设置为取消选中状态
    this.setChecked(false);
   }

   public void run() {
    //如果此时选中,则为表格设置过滤器
    if (isChecked())
     table.addFilter(femaleFilter );
    else//否则,移除表格过滤器
     table.removeFilter(femaleFilter);
    //刷新表格数据
    table.refresh();
   }
}
}

从以上程序的代码中总结出使用TableViewer对象时应注意以下问题:
◆ 创建TableViewer的构造方法:
    ◇ TableViewer(Composite parent):使用默认的样式。
    ◇ TableViewer(Composite parent, int style):可设置表格的样式,样式常量可以使用Table类使用的样式常量。
    ◇ TableViewer(Table table):可以将一个SWT表格对象作为构造函数。
◆ TableViewer中的Table对象:TableViewer实际上封装了SWT的Table对象,通过table.getTable()可以获得该Table对象,表头的设置和显示与SWT的表格的方法相同。
◆ 显示表格的一般步骤:虽然TableViewer内部使用了Table对象,但创建表格数据的代码中并不用创建TableItem来组织数据,因为TableViewer将组织和显示的数据交给了两个接口对象IContentProvider和ITableLabelProvider。
    IContentProvider负责将setInput方法传入的对象转化为表格所需要的对象。ITableLabelProvider负责处理如何显示数据。
    要组织表格数据并显示数据,必须使用以下3个方法:
     //设置数据
   table.setContentProvider(new MyContentProvider());
   //设置视图
   table.setLabelProvider( new MyLabelProvider());
   //设置表格数据对象,该方法非常重要,是表格数据入口
   table.setInput(persons);


◆ 表格中数据组织与两个方法有关:
    ◇ void setInput(Object input):该方法是表格数据最初的入口点,任何对象都可以设置为表格数据,因为该方法所设定的对象为Object对象,所有的类都是Object子类。但通常使用集合类来组织数据。
    在实际的项目开发中,一般会使用实体对象(Entity Object)来装载数据库中的数据,例如本例中的PersonEO实体对象:
package www.swt.com.ch19;

public class PersonEO {
private int ID;
private String name;
private String gender;
private String color;
public PersonEO (){}
public PersonEO ( int id , String name , String gender, String color){
   this.ID = id;
   this.name = name;
   this.gender = gender;
   this.color = color;
}
public String getColor() {
   return color;
}
public void setColor(String color) {
   this.color = color;
}
public String getGender() {
   return gender;
}
public void setGender(String gender) {
   this.gender = gender;
}
public int getID() {
   return ID;
}
public void setID(int id) {
   ID = id;
}
public String getName() {
   return name;
}
public void setName(String name) {
   this.name = name;
}
}

从该实体类中可以看出,该类的属性对应表中的一列。除了列属性外,还有设置和获取属性的方法。
    ◇ setContentProvider方法为表格创建一个规则,使初始化的数据对象转化为表格中的数据。
void setContentProvider(IContentProvider provider)
IContentProvider 是一个接口,而在表格使用时实现IStructuredContentProvider这个接口,该接口继承自IContentProvider 。
    参考本文中的:MyContentProvider 。
    实现IStructuredContentProvider接口必须实现3个方法。其中最重要的是getElements方法。该方法主要将setInput设置的对象转化成表格所使用的数组对象。为防止类型转换异常,在不知道是何类型的情况下可以使用以下代码进行类型检查:
   public Object[] getElements(Object inputElement) {
    if ( inputElement instanceof List )
     return ((List) inputElement).toArray();
    return null;
   }


◆ setLabelProvider(IBaseLabelProvider labelProvider):使用该方法显示数据。IBaseLabelProvider是一个接口,在表格中可以通过实现ITableLabelProvider接口,这个接口是IBaseLabelProvider的子类。
参考本文中的:MyLabelProvider。
    在实现该接口中,最重要的是实现getColumnImage和getColumnText方法。一个是设置单元格的图标,一个是设置单元格显示的文本。

◆ createContextMenu():创建菜单。
参考本文中的:createContextMenu、AddAction、DelAction。
    对表格操作的一些常用的方法:
    ◇ 添加一行数据:add(Object element)。
    ◇ 添加多行数据:add(Object[] elements)。
    ◇ 清空指定表格索引一行的数据:clear(int index)。
    ◇ 在表格指定的索引行插入一行:insert(Object element, int position)。
    ◇ 删除指定的行:remove(Object element)。
    ◇ 删除指定的多行:remove(Object[] elements)。
    ◇ 替换指定行数据:replace(Object element, int index)。
    
    注意:这些方法只是对表格显示的数据进行添加和删除,并未改变数据模型中提供的数据,在本例中数据模型中的数据也就是List对象。也可以通过改变模型中的数据来实现对表格的添加和修改,然后使用refresh()方法刷新表格。

◆ setSorter(ViewerSorter sorter):为表格设置一个排序器。
设置排序器:
   //设置排序器
   table.setSorter( new TableSorter());

排序器的代码如下:
package www.swt.com.ch19;

import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;

public class TableSorter extends ViewerSorter {
private static final int ASCENDING = 0;
private static final int DESCENDING = 1;

private int order;//判断是升序还是降序
private int column;//判断排序的列

public void doSort(int column) {
   // 如果是同一列,改变排列的顺序
   if (column == this.column) {
    order = 1 - order;
   } else {// 如果是另一列,则默认为升序排列
    this.column = column;
    order = ASCENDING;
   }
}
//覆盖父类的方法,返回比较结果有-1,0,1三种情况
public int compare(Viewer viewer, Object e1, Object e2) {
   int result = 0;

   PersonEO p1 = (PersonEO) e1;
   PersonEO p2 = (PersonEO) e2;
  
   //默认是升序
   switch (column) {
   case TableWindow.ID:
    result = p1.getID() > p2.getID() ? 1 : -1;
    break;
   case TableWindow.NAME:
    result = collator.compare(p1.getName(), p2.getName());
    break;
   case TableWindow.GENDER:
    result = collator.compare(p1.getGender(), p2.getGender());
    break;
   case TableWindow.COLOR:
    result = collator.compare(p1.getColor(), p2.getColor());
    break;
   }
   //如果此时为降序
   if (order == DESCENDING)
    result = -result;
   return result;
}
}

    doSort为单击表头时调用,判断数据排序的方法是覆盖父类中的compare()方法,该方法的返回值用于判断数据的顺序。
    有了排序器对象后,下面为表头注册单击表头事件,在初始化表头对象后,在程序中增加以下代码:
   //设置排序器
   table.setSorter( new TableSorter());
   //分别为表头的每一列注册事件
   TableColumn column = table.getTable().getColumn(0);
   column.addSelectionListener( new SelectionAdapter(){
    public void widgetSelected(SelectionEvent e) {
     //单击时,重新设置排序对象属性
     ((TableSorter)table.getSorter()).doSort(TableWindow.ID);
     //刷新表格数据
     table.refresh();
    }
   });
   column = table.getTable().getColumn(1);
   column.addSelectionListener( new SelectionAdapter(){
    public void widgetSelected(SelectionEvent e) {
     ((TableSorter)table.getSorter()).doSort(TableWindow.NAME);
     table.refresh();
    }
   });
   column = table.getTable().getColumn(2);
   column.addSelectionListener( new SelectionAdapter(){
    public void widgetSelected(SelectionEvent e) {
     ((TableSorter)table.getSorter()).doSort(TableWindow.GENDER);
     table.refresh();
    }
   });
   column = table.getTable().getColumn(3);
   column.addSelectionListener( new SelectionAdapter(){
    public void widgetSelected(SelectionEvent e) {
     ((TableSorter)table.getSorter()).doSort(TableWindow.COLOR);
     table.refresh();
    }
   });

    当不需要排序器时,setSorter(null)方法将排序器设置为null就可以了。

◆ addFilter(ViewerFilter filter):为表格设置过滤器。
创建菜单项时增加:menu.add(new FilterAction());
FilterAction的代码参考本文中的:FileterAction。
    当创建过滤器对象时,必须实现select方法,该方法返回布尔型,true表示显示该数据,false表示不显示该数据。
    向表格中设置和移除过滤器的方法是addFilter和removeFilter方法。

◆ 编辑表格单元:所有的单元格编辑器都是从CellEditor继承而来的,该类是一个抽象类,创建对象时要使用实现了的子类。
   //设置列属性
   table.setColumnProperties( COLUMN_NAME );

   //设置单元格编辑器对象数组
     CellEditor[] editors = new CellEditor[4];
     editors[0] = null;
     editors[1] = new TextCellEditor(table.getTable());
     editors[2] = new TextCellEditor(table.getTable());
     editors[3] = new TextCellEditor(table.getTable());
     //设置单元格编辑器
     table.setCellEditors(editors);
   //设置单元个修改器
   table.setCellModifier( new ICellModifier(){
   
    //如果该列为第一列,设置不能修改
    public boolean canModify(Object element, String property) {
     if ( property.equals(COLUMN_NAME[0]))
      return false;
     return true;
    }
    //当处于编辑状态时所显示的值
    public Object getValue(Object element, String property) {
     PersonEO p = (PersonEO) element;
     if ( property.equals(COLUMN_NAME[1]))
      return p.getName();
     else if ( property.equals(COLUMN_NAME[2]))
      return p.getGender();
     else if ( property.equals(COLUMN_NAME[3]))
      return p.getColor();
     return null;
    }
    //当修改后设置更新数据
    public void modify(Object element, String property, Object value) {
     if (element instanceof Item)
      element = ((Item) element).getData();
     PersonEO p = (PersonEO) element;
     if ( property.equals(COLUMN_NAME[1]))
      p.setName( (String)value );
     else if ( property.equals(COLUMN_NAME[2]))
      p.setGender( (String)value );
     else if ( property.equals(COLUMN_NAME[3]))
      p.setColor( (String)value );
     //刷新表格
     table.refresh();
    }
   
   });


◆ 表格的事件处理:
    ◇ 鼠标双击事件:
   table.addDoubleClickListener( new IDoubleClickListener(){
    public void doubleClick(DoubleClickEvent event) {
     StructuredSelection select = (StructuredSelection) event.getSelection();
     PersonEO p = (PersonEO) select.getFirstElement();
     System.out.println(p.getName());
    }
   } );

    ◇ 支持拖动事件:
addDragSupport(int operations, Transfer[] transferTypes, DragSourceListener listener)
addDropSupport(int operations, Transfer[] transferTypes, final DropTargetListener listener)
    ◇ 帮助事件:addHelpListener(HelpListener listener)。
    ◇ 选中改变事件:addSelectionChangedListener(ISelectionChangedListener listener)。
    ◇ 选中改变后事件:addPostSelectionChangedListener(ISelectionChangedListener listener)。
    ◇ 双击打开事件:addOpenListener(IOpenListener listener)。

◆ 带有复选框表格(CheckBoxTableViewer)
   table = CheckboxTableViewer.newCheckList( parent , SWT.FULL_SELECTION);

    CheckboxTableViewer类还提供了对选中状态操作的一些方法:
    ◇ 该行是否已选中:boolean getChecked(Object element)。
    ◇ 获得所有已选中的行:Object[] getCheckedElements()。
    ◇ 该行是否灰色显示:getGrayed(Object element)。
    ◇ 获得所有灰色显示的行:Object[] getGrayedElements()。
    ◇ 设置全选和取消全选:setAllChecked(boolean state)。
    ◇ 设置全部灰色显示和取消灰色显示:setAllGrayed(boolean state)。
    ◇ 设置指定行的选中状态:setChecked(Object element, boolean state)。
    ◇ 设置选中多行:setCheckedElements(Object[] elements)。
    ◇ 设置指定行是否灰色显示的状态:setGrayed(Object element, boolean state)。
    ◇ 设置多行灰色显示:setGrayedElements(Object[] elements)。

界面显示效果:

按性别排序:



筛选后,只显示性别为“女”的:

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
eclipse popupMene高级教程:使用Visibility定制弹出菜单
JAVA.SWT/JFace: SWT高级控件之表格(Table、TableItem和Ta...
解读 LWUIT 之六:使用表格(Table)和树(Tree)
JTable的用法
使用Eclipse RCP创建视图并实现视图间消息传递
使用Eclipse RCP进行桌面程序开发(三):视图和透视图 - 海边沫沫 - Blog...
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服