jface databinding:重写doSetValue方法ComputedValue实现双向多对一的数据绑定

需求说明

如下是一个简单的测试对话框,我们希望当”起始日期”按钮为勾选时,数据对象dataBean的date属性为日期组件DateTime选择的值,否则为null.

先给出DateBean的类定义

    // 具备PropertyChangeSupport支持的JavaBean
    public class DateBean{
        private PropertyChangeSupport support=new PropertyChangeSupport(this);
        public void addPropertyChangeListener(PropertyChangeListener listener) {
            support.addPropertyChangeListener(listener);
        }

        public void removePropertyChangeListener(PropertyChangeListener listener) {
            support.removePropertyChangeListener(listener);
        }

        public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
            support.firePropertyChange(propertyName, oldValue, newValue);
        }

        Date date;

        public Date getDate() {
            return date;
        }

        public void setDate(Date date) {
            System.out.printf("date=%s\n", date);
            firePropertyChange("date", this.date, this.date = date);
        }

ISideEffect

在这个场景中,是两个widget组件的状态绑定到一个数据对象的属性 实现上面的需求,参考我之前的博文《jface databinding:更简单的ISideEffect实现多目标单边数据绑定塈其原理分析》,可以很简单的实现。

    DateTime dateTime=new DateTime(container, SWT.BORDER);
    Button chkDateEnable=new Button(container, SWT.CHECK);
    //。。。。。
    DataBindingContext bindingContext = new DataBindingContext();
    // 创建dateTime日期组件的观察对象
    IObservableValue observeSelectionDateTimeObserveWidget = WidgetProperties.selection().observe(dateTime);
    // 创建chkDateEnable按钮的观察对象
    IObservableValue observeSelectionChkDateEnableObserveWidget = WidgetProperties.selection().observe(chkDateEnable);
    // 创建ISideEffect实现dateTime+chkDateEnable->dateBean.date的单向数据绑定
    ISideEffect.create(()->{
        return (boolean)observeSelectionChkDateEnableObserveWidget.getValue()?(Date)observeSelectionDateTimeObserveWidget.getValue():null;
    }, dateBean::setDate);

ComputedValue

但是,上面的代码只是实现了单向的数据绑定,如果希望在上图中按”恢复缺省值”时,dateBean.date修改后,界面的chkDateEnable和dateTime组件也同步更新,就不能使用ISideEffect了。

我们知道ComputedValue也可以实现单向的多对一数组绑定,

关于ComputedValue,我在另一篇博文中有更详细的介绍《jface databinding:延迟计算–ComputedValue和WritableList使用的例子》

但ComputedValue并没有实现doSetValue方法,所以如果对ComputedValue对象执行setValue方法会抛出UnsupportedOperationException异常,所以ComputedValue是单向的绑定。但是如果我们实现了doSetValue方法,就可以实现双向的数据绑定。

    DateTime dateTime=new DateTime(container, SWT.BORDER);
    Button chkDateEnable=new Button(container, SWT.CHECK);
    //。。。。。
    DataBindingContext bindingContext = new DataBindingContext();
    // 创建dateTime日期组件的观察对象
    IObservableValue observeSelectionDateTimeObserveWidget = WidgetProperties.selection().observe(dateTime);
    // 创建chkDateEnable按钮的观察对象
    IObservableValue observeSelectionChkDateEnableObserveWidget = WidgetProperties.selection().observe(chkDateEnable);
    // 创建ComputedValue对象
    IObservableValue<Date> observableDate = new ComputedValue<Date>(){
        // 重写doSetValue,
        // 当value为null时,chkDateEnable不勾选,dateTime设置为disable
        // value不为null时,chkDateEnable勾选,dateTime设置为enable,并将dateTime组件的日期设置为value的日期
        @Override
        protected void doSetValue(Date value) {
            chkDateEnable.setSelection(null!=value);
            dateTime.setEnabled(null!=value);
            if(null!=value){
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(value);
                dateTime.setDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONDAY), calendar.get(Calendar.DAY_OF_MONTH));
            }                   
        }

        @Override
        protected Date calculate() {
            // 根据chkDateEnable的selection状态,返回Date对象
            // chkDateEnable.selection为true时,返回dateTime的值,设置dateTime为enable
            // chkDateEnable.selection为false时,返回null,设置dateTime为disable
            boolean selection = (boolean)observeSelectionChkDateEnableObserveWidget.getValue();
            dateTime.setEnabled(selection);
            return selection?(Date)observeSelectionDateTimeObserveWidget.getValue():null;
        }

    };
    // 对observableDate对象与dateBean.date属性进行数据绑定
    bindingContext.bindValue(observableDate, dateDateBeanObserveValue, null, null);

完整示例代码

TestComputedValue2 .java

package testwb;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Calendar;
import java.util.Date;

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.Shell;


import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.sideeffect.ISideEffect;
import org.eclipse.core.databinding.observable.value.ComputedValue;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.databinding.swt.DisplayRealm;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;

public class TestComputedValue2 extends Dialog {
    private DataBindingContext m_bindingContext;
    public class DateBean{
        private PropertyChangeSupport support=new PropertyChangeSupport(this);
        public void addPropertyChangeListener(PropertyChangeListener listener) {
            support.addPropertyChangeListener(listener);
        }

        public void removePropertyChangeListener(PropertyChangeListener listener) {
            support.removePropertyChangeListener(listener);
        }

        public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
            support.firePropertyChange(propertyName, oldValue, newValue);
        }

        Date date;

        public Date getDate() {
            return date;
        }

        public void setDate(Date date) {
            System.out.printf("date=%s\n", date);
            firePropertyChange("date", this.date, this.date = date);
        }
    }
    private DateBean dateBean=new DateBean();
    private DateTime dateTime;
    private Button chkDateEnable;
    /**
     * Create the dialog.
     * @param parentShell
     */
    public TestComputedValue2(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);

        dateTime = new DateTime(container, SWT.BORDER);
        dateTime.setBounds(86, 95, 88, 24);

        chkDateEnable = new Button(container, SWT.CHECK);
        chkDateEnable.setBounds(10, 99, 70, 17);
        chkDateEnable.setText("起始日期");

        Button btnNewButton = new Button(container, SWT.NONE);
        btnNewButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                dateBean.setDate(new Date());
            }
        });
        btnNewButton.setBounds(10, 167, 80, 27);
        btnNewButton.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);
    }
    protected DataBindingContext initDataBindings() {
        DataBindingContext bindingContext = new DataBindingContext();
        //
        IObservableValue observeSelectionDateTimeObserveWidget = WidgetProperties.selection().observe(dateTime);
        IObservableValue observeSelectionChkDateEnableObserveWidget = WidgetProperties.selection().observe(chkDateEnable);
        IObservableValue dateDateBeanObserveValue = BeanProperties.value("date").observe(dateBean);
        //bindingContext.bindValue(observeSelectionDateTimeObserveWidget, dateDateBeanObserveValue, null, null);
        /*IObservableValue<Date> observableDate = ComputedValue.create(()->{
            return chkDateEnable.getSelection()?(Date)observeSelectionDateTimeObserveWidget.getValue():null;
        });*/
        // 创建ComputedValue对象
        IObservableValue<Date> observableDate = new ComputedValue<Date>(){
            // 重写doSetValue,
            // 当value为null时,chkDateEnable不勾选,dateTime设置为disable
            // value不为null时,chkDateEnable勾选,dateTime设置为enable,并将dateTime组件的日期设置为value的日期
            @Override
            protected void doSetValue(Date value) {
                chkDateEnable.setSelection(null!=value);
                dateTime.setEnabled(null!=value);
                if(null!=value){
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(value);
                    dateTime.setDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONDAY), calendar.get(Calendar.DAY_OF_MONTH));
                }                   
            }

            @Override
            protected Date calculate() {
                // 根据chkDateEnable的selection状态,返回Date对象
                // chkDateEnable.selection为true时,返回dateTime的值,设置dateTime为enable
                // chkDateEnable.selection为false时,返回null,设置dateTime为disable
                boolean selection = (boolean)observeSelectionChkDateEnableObserveWidget.getValue();
                dateTime.setEnabled(selection);
                return selection?(Date)observeSelectionDateTimeObserveWidget.getValue():null;
            }

        };
        // 对observableDate对象与dateBean.date属性进行数据绑定
        bindingContext.bindValue(observableDate, dateDateBeanObserveValue, null, null);
        /*ISideEffect.create(()->{
            return (boolean)observeSelectionChkDateEnableObserveWidget.getValue()?(Date)observeSelectionDateTimeObserveWidget.getValue():null;
        }, dateBean::setDate);*/
        //
        return bindingContext;
    }
    public static void main(String[] args) {
        Display display = Display.getDefault();
        Realm.runWithDefault(DisplayRealm.getRealm(display), new Runnable() {
            public void run() {
                try {
                    TestComputedValue2 setting = new TestComputedValue2(null);
                    setting.open();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术碎碎念

windows API 开发飞机订票系统 图形化界面 (三)

来吧,接下来是各个功能的函数的实现代码。 首先,程序运行时加载读入账户信息和航班信息。接下来就该读取文件了。 我把账户资料和航班信息储存在了.txt文件里 那么...

40414
来自专栏Google Dart

Flutter 构建完整应用手册-列表 顶

显示数据列表是移动应用程序的基本模式。 Flutter包含ListView部件,使列表变得轻而易举!

1172
来自专栏跟着阿笨一起玩NET

DateTime.TryParseExact 万能时间格式转化

本文转载:http://blog.csdn.net/gaofang2009/article/details/6073231

891
来自专栏码匠的流水账

聊聊flink LocalEnvironment的execute方法

flink-java-1.6.2-sources.jar!/org/apache/flink/api/java/DataSet.java

553
来自专栏向治洪

ormlite介绍一

概述 ORMlite是类似hibernate的对象映射框架,主要面向java语言,同时,是时下最流行的android面向数据库的的编程工具。 官方网站:http...

1856
来自专栏SeanCheney的专栏

《Pandas Cookbook》第08章 数据清理1. 用stack清理变量值作为列名2. 用melt清理变量值作为列名3. 同时stack多组变量4. 反转stacked数据5. 分组聚合后uns

第01章 Pandas基础 第02章 DataFrame运算 第03章 数据分析入门 第04章 选取数据子集 第05章 布尔索引 第06章 索引对齐 ...

692
来自专栏圆方圆学院精选

【许晓笛】 EOS 智能合约案例解析(2)

之前的文章介绍了 eosio.token 智能合约的 hpp 文件,这次向大家介绍 eosio.token.cpp 文件,cpp 文件即 C++ 代码文件,智能...

1015
来自专栏函数式编程语言及工具

PICE(5):MongoDBStreaming - gRPC -MGO Service

  我在前面提到过MongoDB不支持像SQL般字符式的操作指令,所以我们必须对所有的MongoDB操作指令建立protobuf类型才能支持MongoDB指令的...

684
来自专栏数据之美

Pig、Hive 自定义输入输出分隔符以及Map、Array嵌套分隔符冲突问题

PIG中输入输出分隔符默认是制表符\t,而到了hive中,默认变成了八进制的\001, 也就是ASCII: ctrl - A Oct   Dec   Hex  ...

2105
来自专栏前端儿

键盘中断事件及其相关---小记

当我们在按下按键时,键盘会把按键的扫描码发送到主板的接口电路中,具体说就是端口60H。

872

扫码关注云+社区