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

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

需求说明

如下图,一个可多选的List组件,初始表有3个值,希望实现与一个java.util.List对象(保存选中的值)的双向数据绑定。当List组件中选中的内容变化时,java.util.List对象的内容也同步变化。

实现Observable对象

我们知道,org.eclipse.jface.databinding.swt.WidgetProperties工厂类的items()方法中为CCombo、Combo、List提供了获取表中所有条目(item)的observable对象,但是这个observable对象关注的是表中所有条目而不是选中的条目。所以不能满足需求。 参见 org.eclipse.jface.internal.databinding.swt.ListItemsProperty的源码

public class ListItemsProperty extends ControlStringListProperty {
    @Override
    protected void doUpdateStringList(final Control control, ListDiff diff) {
        diff.accept(new ListDiffVisitor() {
            List list = (List) control;

            @Override
            public void handleAdd(int index, Object element) {
                list.add((String) element, index);
            }

            @Override
            public void handleRemove(int index, Object element) {
                list.remove(index);
            }

            @Override
            public void handleReplace(int index, Object oldElement,
                    Object newElement) {
                list.setItem(index, (String) newElement);
            }
        });
    }

    @Override
    public String[] doGetStringList(Control control) {
        // getter方法调用List.getItems返回的是表中所有内容。
        return ((List) control).getItems();
    }

    @Override
    public String toString() {
        return "List.items[] <String>"; //$NON-NLS-1$
    }
}

所以如果想实现上面的需求,就得不能用WidgetProperties工厂类提供的observable对象,要动手自己实现Observable类了,好在有了ListItemsProperty 方法的代码,参照它就可以根据自己的需求写一个新的类了。

ListSelectedItemsProperty1.java

package net.gdface.ui;

import org.eclipse.core.databinding.observable.list.ListDiff;
import org.eclipse.core.databinding.observable.list.ListDiffVisitor;
import org.eclipse.core.databinding.property.INativePropertyListener;
import org.eclipse.core.databinding.property.ISimplePropertyListener;
import org.eclipse.jface.internal.databinding.swt.ListItemsProperty;
import org.eclipse.jface.internal.databinding.swt.WidgetListener;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.List;

/**
 * List组件中选中项目的Observable对象实现<br>
 * 对List组件表中内容的增加,删除操作不会改变表中内容,只会改变对应的selected状态
 * @author guyadong
 *
 */
public class ListSelectedItemsProperty1 extends ListItemsProperty {
    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    protected void doUpdateStringList(final Control control, ListDiff diff) {
        diff.accept(new ListDiffVisitor() {
            List list = (List) control;
            @Override
            public void handleAdd(int index, Object element) {
                // element对应的item置为selected
                list.select(find((String) element));
            }

            @Override
            public void handleRemove(int index, Object element) {
                // element对应的item置为unselected
                list.deselect(find((String) element));
            }

            @Override
            public void handleReplace(int index, Object oldElement,
                    Object newElement) {
            }
            /**
             * 在List中查找指定字符串的索引,找不到则返回-1
             * @param element
             * @return
             */
            private int find(String element){
                int count = list.getItemCount ();
                for(int i=0;i<count;++i){
                    if(list.getItem(i).equals(element))return i;
                }
                return -1;
            }
        });
    }
    @Override
    public  String[] doGetStringList(Control control) {
        // 返回所有选中的item
        return ((List) control).getSelection();
    }
    // 重写adaptListener方法,返回NativePropertyListener对象,
    // 否则外部不能检测到List组件的状态变化
    @SuppressWarnings({ "rawtypes" })
    @Override
    public INativePropertyListener adaptListener(ISimplePropertyListener listener) {        
        return new WidgetListener(this, listener, new int[]{SWT.Selection}, null);
    }

}

测试代码

TestList.java

package testwb;

import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.core.databinding.observable.sideeffect.ISideEffect;
import org.eclipse.jface.databinding.swt.DisplayRealm;
import org.eclipse.jface.databinding.swt.ISWTObservableList;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.graphics.Point;
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 net.gdface.ui.ListSelectedItemsProperty1;

import org.eclipse.swt.widgets.List;
import org.eclipse.swt.SWT;

import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;

public class TestList extends Dialog {
    private DataBindingContext m_bindingContext;
    // 数据对象
    private WritableList<String> observableList=new WritableList<String>();
    private List list;
    private Label lblSelected;
    /**
     * Create the dialog.
     * @param parentShell
     */
    public TestList(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(null);
        // 初始化数据对象
        observableList.add("apple");
        list = new List(container, SWT.BORDER | SWT.MULTI);
        // 初始化List组件中的内容
        list.add("apple");
        list.add("orange");
        list.add("banana");
        list.setBounds(10, 31, 231, 68);

        lblSelected = new Label(container, SWT.BORDER);
        lblSelected.setBounds(10, 153, 424, 32);

        Label label = new Label(container, SWT.NONE);
        label.setBounds(10, 130, 61, 17);
        label.setText("已选择");

        Button btnAdd = new Button(container, SWT.NONE);
        btnAdd.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                if(!observableList.contains("banana"))observableList.add("banana");
            }
        });
        btnAdd.setBounds(286, 30, 80, 27);
        btnAdd.setText("增加");

        Button btnClear = new Button(container, SWT.NONE);
        btnClear.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                observableList.clear();
            }
        });
        btnClear.setBounds(286, 105, 80, 27);
        btnClear.setText("清除");

        Button btnDelete = new Button(container, SWT.NONE);
        btnDelete.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                observableList.remove("apple");
            }
        });
        btnDelete.setBounds(286, 63, 80, 27);
        btnDelete.setText("删除");

        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);
        m_bindingContext = initDataBindings();
    }

    /**
     * Return the initial size of the dialog.
     */
    @Override
    protected Point getInitialSize() {
        return new Point(450, 300);
    }
    public static void main(String[] args) {
        Display display = Display.getDefault();
        Realm.runWithDefault(DisplayRealm.getRealm(display), new Runnable() {
            public void run() {
                try {
                    TestList testList = new TestList(null);
                    testList.open();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    protected DataBindingContext initDataBindings() {
        DataBindingContext bindingContext = new DataBindingContext();
        // 调用ListSelectedItemsProperty1为List组件创建observable对象
        ISWTObservableList observeSelectedListObserveWidget =new ListSelectedItemsProperty1().observe(list);
        // 将List组件与数据对象observableList绑定在一起
        bindingContext.bindList(observeSelectedListObserveWidget, observableList, null, null);
        // 为查看数据对象observableList的内容,将之与Label组件进行单向绑定,
        // observableList的内容变化能及时显示在Label中
        ISideEffect.create(
            observableList::size, (s)->{
            lblSelected.setText(String.join(",", observableList));
        });
        return bindingContext;
    }
}

注意

ListSelectedItemsProperty1.java的父类org.eclipse.jface.internal.databinding.swt.ListItemsProperty在jface.internal包下,也就是非公开的包,所以这个类的接口稳定性并没有保证,版本升级的时候有可能会被改变或删除。 ListSelectedItemsProperty1中用到的WidgetListener类也是同样的问题。 如果要解决这个问题,应该把该类及其父类的代码复制出来重写才是最保险的。 如下为以WidgetListProperty为父类重写的ListSelectedItemsProperty2,不使用jface.internal包下的类 ListSelectedItemsProperty2.java

package net.gdface.ui;

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

import org.eclipse.core.databinding.observable.list.ListDiff;
import org.eclipse.core.databinding.observable.list.ListDiffVisitor;
import org.eclipse.core.databinding.property.INativePropertyListener;
import org.eclipse.core.databinding.property.ISimplePropertyListener;
import org.eclipse.core.databinding.property.NativePropertyListener;
import org.eclipse.jface.databinding.swt.WidgetListProperty;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;

public class ListSelectedItemsProperty2 extends WidgetListProperty {
    @Override
    public Object getElementType() {
        return String.class;
    }

    @SuppressWarnings("rawtypes")
    @Override
    protected void doSetList(Object source, List list, ListDiff diff) {
        doUpdateList(source, diff);
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    protected void doUpdateList(Object source, ListDiff diff) {
        diff.accept(new ListDiffVisitor() {
            org.eclipse.swt.widgets.List list = (org.eclipse.swt.widgets.List) source;
            @Override
            public void handleAdd(int index, Object element) {
                list.select(find((String) element));
            }

            @Override
            public void handleRemove(int index, Object element) {
                list.deselect(find((String) element));
            }

            @Override
            public void handleReplace(int index, Object oldElement,
                    Object newElement) {
            }
            /**
             * 在List中查找指定字符串的索引,找不到则返回-1
             * @param element
             * @return
             */
            private int find(String element){
                int count = list.getItemCount ();
                for(int i=0;i<count;++i){
                    if(list.getItem(i).equals(element))return i;
                }
                return -1;
            }
        });
    }


    @SuppressWarnings("rawtypes")
    @Override
    protected List doGetList(Object source) {
        return Arrays.asList(((org.eclipse.swt.widgets.List) source).getSelection());
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    public INativePropertyListener adaptListener(ISimplePropertyListener listener) {
        // 继承NativePropertyListener实现INativePropertyListener 接口
        return new NativePropertyListener(this,listener){
            private final SelectionListener selectionListener=new SelectionListener(){
                @Override
                public void widgetSelected(SelectionEvent e) {
                    fireChange(e.getSource(), null);        
                }
                @Override
                public void widgetDefaultSelected(SelectionEvent e) {
                    fireChange(e.getSource(), null);                    
                }};
            @Override
            protected void doAddTo(Object source) {
                ((org.eclipse.swt.widgets.List)source).addSelectionListener(selectionListener);
            }

            @Override
            protected void doRemoveFrom(Object source) {
                ((org.eclipse.swt.widgets.List)source).removeSelectionListener(selectionListener);
            }
        };
    }
}

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

我来说两句

0 条评论
登录 后参与评论

相关文章

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

    显示需求 如下图,希望将一组拥有两个字段的表与两列的table绑定在一起,实现自动显示。 ? 在jface viewer中label provide...

    用户1148648
  • jface databinding:使用CheckboxTableViewer实现表中(Set)对象与CheckTable中选中条目数据绑定

    上一篇博文《jface databinding:可多选的widget List组件selection项目与java.util.List对象的双向数据绑定》讲述了...

    用户1148648
  • jface databinding(数据挷定)中的数据转换(IConverter)和数据验证(IValidator )

    版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net...

    用户1148648
  • 从6万用户评论中,他们选出了23门全世界最好的CS免费课

    全世界范围内,有大概1000所大学发布了超过13000门免费公开课了,而且数量每年都会增长。

    量子位
  • golang爬虫初体验

    最近在学习golang,看网上很多人都喜欢爬豆瓣,今天我就写了一个golang版的爬虫。对于python爬虫,我很了解,什么dom树,js异步,爬虫技术栈都是没...

    若与
  • 【连载15】Residual Networks、Maxout Networks和Network in Network

    残差网络在《Deep Residual Learning for Image Recognition》中被第一次提出,作者利用它在ILSVRC 2015的Ima...

    lujohn3li
  • MySQL8.0本地访问设置为远程访问权限

    查看表格中 root 用户的 host,默认应该显示的 localhost,只支持本地访问,不允许远程访问。

    拓荒者
  • 如何将自己的jar包发布到mavan中央仓库

    这里有一个小小的坑就是如果你没有域名的话groupId可以写com.github.你的github名或者io.github.你的github名。如果你写域名的...

    Java学习录
  • Java数组转List的三种方式及对比

    本文介绍Java中数组转为List三种情况的优劣对比,以及应用场景的对比,以及程序员常犯的类型转换错误原因解析。

    Java编程指南
  • Perl在ASIC中的应用——高级篇(1):正则表达式

    从今天开始,我们介绍Perl在ASIC应用中的高级篇。高级篇主要介绍正则表达式、module、package、面向对象、进程等。

    ExASIC

扫码关注云+社区

领取腾讯云代金券