jface databinding:label provider 实现多列表格(Table)数据绑定的两个途径

显示需求

如下图,希望将一组拥有两个字段的表与两列的table绑定在一起,实现自动显示。

在jface viewer中label provider用于提供数据对象到视图对象(viewer)显示内容的数据映射关系。也就是实现将数据模型中的不同字段的内容显示为viewer(如表格Table组件)中的文字或图像。 如下图IBaseLabelProvider是所有label provider的顶层抽象接口

实现上述这个需求,就是要找到合适的label provider。对于TableViewer,需要为每一列数据都要有对应文本,所以其适用的label provider是ITableLabelProvider接口实现。

ViewSupport

如果这两个字段的数据对象是有getter方法(不一定要求有setter方法),而且字段的类型都有合适的toString()方法将变量转为字符串,那么事情就变得简单:用ViewSupport就能很方便的实现绑定。 ViewSupport.bind方法会自动为提供ITableLabelProvider对象并准确实现数据对象的字段到表格中列的关系映射。 下面是ViewerSupport.bind(StructuredViewer viewer, IObservableList input, IValueProperty… labelProperties) 方法的实现代码

    public static void bind(StructuredViewer viewer, IObservableList input, IValueProperty... labelProperties) {
        ObservableListContentProvider contentProvider = new ObservableListContentProvider();
        if (viewer.getInput() != null)
            viewer.setInput(null);
        viewer.setContentProvider(contentProvider);
        // 创建ObservableMapLabelProvider对象作为label provider
        viewer.setLabelProvider(new ObservableMapLabelProvider(Properties
                .observeEach(contentProvider.getKnownElements(),
                        labelProperties)));
        if (input != null)
            viewer.setInput(input);
    }

核心实现代码,一行代码就搞定绑定

        TableViewer tableViewer = new TableViewer(container, SWT.BORDER | SWT.FULL_SELECTION);
        table = tableViewer.getTable();
        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        TableColumn tblclmnId = new TableColumn(table, SWT.NONE);
        tblclmnId.setWidth(100);
        tblclmnId.setText("ID");

        TableColumn tblclmnName = new TableColumn(table, SWT.NONE);
        tblclmnName.setWidth(100);
        tblclmnName.setText("Name");
        // 这里使用org.javatuples.Pair作为数据对象元素的类
        // org.javatuples.Pair有getValue0,getValue1方法用于分别获取两个成员变量
        IObservableList<Pair<Integer,String>> input=createInput();// 创建ObservableList作为输入
        // PojoProperties.values方法生成指定字段的IBeanValueProperty对象
        ViewerSupport.bind(tableViewer, input,
                PojoProperties.
                values(new String[] { "value0", "value1"}));

完整测试代码

以下是WindowBuilder生成的测试代码。

注意需要javatuples的jar包支持

TestTableProvider.java

package testwb;

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

import org.eclipse.core.databinding.beans.PojoProperties;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.property.Properties;
import org.eclipse.jface.databinding.swt.DisplayRealm;
import org.eclipse.jface.databinding.viewers.ViewerSupport;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.javatuples.Pair;

import org.eclipse.jface.viewers.TableViewer;

public class TestTableProvider extends Dialog {
    private Table table;

    /**
     * Create the dialog.
     * @param parentShell
     */
    public TestTableProvider(Shell parentShell) {
        super(parentShell);
    }

    /**
     * Create contents of the dialog.
     * @param parent
     */
    @Override
    protected Control createDialogArea(Composite parent) {
        Composite container = (Composite) super.createDialogArea(parent);
        container.setLayout(new FillLayout(SWT.HORIZONTAL));

        TableViewer tableViewer = new TableViewer(container, SWT.BORDER | SWT.FULL_SELECTION);
        table = tableViewer.getTable();
        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        TableColumn tblclmnId = new TableColumn(table, SWT.NONE);
        tblclmnId.setWidth(100);
        tblclmnId.setText("ID");

        TableColumn tblclmnName = new TableColumn(table, SWT.NONE);
        tblclmnName.setWidth(100);
        tblclmnName.setText("Name");
        ViewerSupport.bind(tableViewer, createInput(),
                PojoProperties.
                values(new String[] { "value0", "value1"}));
        return container;
    }

    /**
     * Create contents of the button bar.
     * @param parent
     */
    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
        createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
    }
    @Override
    protected void configureShell(Shell newShell) {
        newShell.setText("数据标签");
        super.configureShell(newShell);
    }
    private IObservableList<Pair<Integer,String>> createInput(){
        List<String> names=Arrays.asList("face","car","bus");
        ArrayList<Pair<Integer,String>> list = new ArrayList<Pair<Integer,String>>();
        for(int i=0;i<names.size();++i){
            list.add(Pair.with(Integer.valueOf(i),names.get(i)));
        }
        return Properties.<Pair<Integer,String>>selfList(Pair.class).observe(list);
    }
    public static void showTable(Shell shell){
        Display display = null==shell?Display.getDefault():shell.getDisplay();
        Realm.runWithDefault(DisplayRealm.getRealm(display), new Runnable() {
            public void run() {
                try {
                    TestTableProvider setting = new TestTableProvider(shell);
                    setting.open();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    public static void main(String[] args) {
        showTable(null);
    }
}

实现ITableLabelProvider接口

如果数据对象中没有定义getter方法,ViewSupport.bind方法就没办法用了。 通过看前面ViewSupport.bind方法的实现代码可以知道,ViewSupport.bind方法中为TableViewer提供了一个ObservableMapLabelProvider对象,实现对数据对象的解析。ObservableMapLabelProvider对象实现了ITableLabelProvider接口,这个接口为Tabler提供每个单元显示的text/image对象。

ITableLabelProvider原文说明: Extends IBaseLabelProvider with the methods to provide the text and/or image for each column of a given element. Used by table viewers.

So,只要实现ITableLabelProvider接口就能为任意类型的数据对象提供每个单元的显示文本。 下图为ITableLabelProvider所在的层次结构图,

虽然ITableLabelProvider只有两个方法,但其父类接口IBaseLabelProvider却还有4个方法。所以如果要直接实现ITableLabelProvider接口,就要实现6个方法,即麻烦也没必要,因为IBaseLabelProvider之下的BaseLabelProvider类,提供了IBaseLabelProvider接口的基本实现,所以,只要自定义的TableLabelProvider,只需要继承BaseLabelProvider再实现ITableLabelProvider就可以了。 So,下面就是根据需求实现的自定义PairTableLabelProvider

    class PairTableLabelProviderextends BaseLabelProvider implements ITableLabelProvider{

        @Override
        public Image getColumnImage(Object element, int columnIndex) {
            return null;
        }

        @Override
        public String getColumnText(Object element, int columnIndex) {
            Pair pair=(Pair) element;
            switch(columnIndex){
            case 0:return pair.a.toString();
            case 1:return pair.b.toString();
            default:return null;
            }
        }

    }

有了PairTableLabelProviderextends类,就可以参照ViewSupport.bind方法实现数据TableViewer与数据对象的绑定了,核心代码如下:

        TableViewer tableViewer = new TableViewer(container, SWT.BORDER | SWT.FULL_SELECTION);
        table = tableViewer.getTable();
        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        TableColumn tblclmnId = new TableColumn(table, SWT.NONE);
        tblclmnId.setWidth(100);
        tblclmnId.setText("ID");

        TableColumn tblclmnName = new TableColumn(table, SWT.NONE);
        tblclmnName.setWidth(100);
        tblclmnName.setText("Name");
        // 以上代码与之前相同
        tableViewer.setContentProvider(new ObservableListContentProvider());
        // 将PairTableLabelProvider作为LabelProvider提供给tableViewer
        tableViewer.setLabelProvider(new PairTableLabelProvider());
        // 这里使用org.eclipse.core.internal.databinding.Pair作为数据对象元素的类
        // org.eclipse.core.internal.databinding.Pair没有getter方法获取类成员变量
        IObservableList<Pair> input=createInput();// 创建ObservableList作为输入
        tableViewer.setInput(input);

完整的测试代码

以下是WindowBuilder生成的测试代码。 TestTableProvider3.java

package testwb;

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

import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.property.Properties;
import org.eclipse.core.internal.databinding.Pair;
import org.eclipse.jface.databinding.swt.DisplayRealm;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
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.Shell;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;

import org.eclipse.jface.viewers.BaseLabelProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.TableViewer;

public class TestTableProvider3 extends Dialog {
    class PairTableLabelProvider extends BaseLabelProvider implements ITableLabelProvider{

        @Override
        public Image getColumnImage(Object element, int columnIndex) {
            return null;
        }

        @Override
        public String getColumnText(Object element, int columnIndex) {
            Pair pair=(Pair) element;
            switch(columnIndex){
            case 0:return (String) pair.a;
            case 1:return (String) pair.b;
            default:return null;
            }
        }

    }
    private Table table;

    /**
     * Create the dialog.
     * @param parentShell
     */
    public TestTableProvider3(Shell parentShell) {
        super(parentShell);
    }

    /**
     * Create contents of the dialog.
     * @param parent
     */
    @Override
    protected Control createDialogArea(Composite parent) {
        Composite container = (Composite) super.createDialogArea(parent);
        container.setLayout(new FillLayout(SWT.HORIZONTAL));

        TableViewer tableViewer = new TableViewer(container, SWT.BORDER | SWT.FULL_SELECTION);
        table = tableViewer.getTable();
        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        TableColumn tblclmnId = new TableColumn(table, SWT.NONE);
        tblclmnId.setWidth(100);
        tblclmnId.setText("ID");

        TableColumn tblclmnName = new TableColumn(table, SWT.NONE);
        tblclmnName.setWidth(100);
        tblclmnName.setText("Name");
        tableViewer.setContentProvider(new ObservableListContentProvider());
        tableViewer.setLabelProvider(new PairTableLabelProvider());
        tableViewer.setInput(createInput());

        return container;
    }

    /**
     * Create contents of the button bar.
     * @param parent
     */
    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
        createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
    }
    @Override
    protected void configureShell(Shell newShell) {
        newShell.setText("数据标签");
        super.configureShell(newShell);
    }
    private IObservableList<Pair> createInput(){
        List<String> names=Arrays.asList("face","car","bus");
        ArrayList<Pair> list = new ArrayList<Pair>();
        for(int i=0;i<names.size();++i){
            list.add(new Pair(i,names.get(i)));
        }
        return Properties.<Pair>selfList(Pair.class).observe(list);
    }
    public static void showAnnotationTable(Shell shell, List<String> selectedFilters){
        Display display = null==shell?Display.getDefault():shell.getDisplay();
        Realm.runWithDefault(DisplayRealm.getRealm(display), new Runnable() {
            public void run() {
                try {
                    TestTableProvider3 setting = new TestTableProvider3(shell);
                    setting.open();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    public static void main(String[] args) {
        showAnnotationTable(null, null);
    }
}

参考资料

《viewersupport》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏葡萄城控件技术团队

最全数据结构详述: List VS IEnumerable VS IQueryable VS ICollection VS IDictionary

本文对常用的数据结构详述:Array, ArrayList,List,IList,ICollection, Stack, Queue, HashTable, D...

2118
来自专栏ASP.NET MVC5 后台权限管理系统

ASP.NET MVC5+EF6+EasyUI 后台管理系统(17)-LinQ动态排序

首先修复程序中的一个BUG这个BUG在GridPager类中,把sord修改为sort这个名称填写错误,会导致后台一直无法获取datagrid的排序字段 本来是...

2005
来自专栏小狼的世界

几个有用的Excel VBA脚本

最近有个朋友要处理很多的Excel数据,但是手工处理又太慢,让我帮忙处理。通过搜索和自己的编写,帮他写了几个脚本,大大提高了工作效率。其实Excel中的脚本(宏...

1032
来自专栏10km的专栏

jface databinding:可多选的widget List组件selection项目与java.util.List对象的双向数据绑定

需求说明 如下图,一个可多选的List组件,初始表有3个值,希望实现与一个java.util.List对象(保存选中的值)的双向数据绑定。当List组件中选中的...

1878
来自专栏听雨堂

VB6对滚轮的支持

        我需要对Mapx控件支持鼠标滚轮,找了一个可以使用的代码,来自         http://blog.csdn.net/areful/arch...

18410
来自专栏猿人谷

mybatis调用视图和存储过程

    现在的项目是以Mybatis作为O/R映射框架,确实好用,也非常方便项目的开发。MyBatis支持普通sql的查询、视图的查询、存储过程调用,是一种非常...

2125
来自专栏ASP.NET MVC5 后台权限管理系统

ASP.NET MVC5+EF6+EasyUI 后台管理系统(81)-数据筛选(万能查询)

前言 听标题的名字似乎是一个非常牛X复杂的功能,但是实际上它确实是非常复杂的,我们本节将演示如何实现对数据,进行组合查询(数据筛选) 我们都知道Excel...

2018
来自专栏Core Net

.Net cache与cache更新

3195
来自专栏cloudskyme

jbpm5.1介绍(7)

Junit测试评估流程 评估流程的界面如下: ? 这个示例里边用到了Script Task,Service Task和User Task Log执行记录日志的...

38411
来自专栏张善友的专栏

Ibatisnet Quick Start

准备工作 1. 下载ibatis软件包(http://ibatis.apache.org/dotnetdownloads.html)。 2. 创建测试数据库,并...

1708

扫码关注云+社区