前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >jface databinding(数据挷定)中的数据转换(IConverter)和数据验证(IValidator )

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

作者头像
10km
发布2019-05-25 22:31:26
8720
发布2019-05-25 22:31:26
举报
文章被收录于专栏:10km的专栏10km的专栏

版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433714

前几天在做对话框界面过程中,对行文本框中的输入数值需要进行验证,于是对Text组件做了扩展,做了一个可以验证输入的字符串是否为数值的NumText组件,参见 《java SWT:限制数值输入的Text文本框通用组件》,但是在使用过程中发现,这种方式有缺陷,就是如果用户输入非法的字符,结果就是输不进去,界面上不会有报错也不会有任何提示,用户体验不好。

之前对databinding有过简单的了解,知道它可以实现UI组件和用户数据之前的同步更新以及数据类型转换和验证,但是觉着它太复杂,我的应用似乎用不上,所以一直没有进一步深入了解。发现自己设计的NumText组件用户体验存在问题后,才下决心对jface databinding做深入的了解。

WindowBuilder下数据绑定操作

如果你已经知道怎么进行数据绑定可以跳过本节

之前看过一些关于jface databinding方面的文章,文章都很长,代码好多,感觉好复杂的样子,一下子把我吓住了,尼玛,这jface databinding本是要简化代码设计的,要是需要写更多更复杂代码,还不累死人呀。

后来发现,在WindowBuilder下数据绑定操作已经可以像UI设计一样在UI界面下点点鼠标就能生成代码了,大大降低了学习门槛,简化了代码编写工作量。

使用WindowBuilder对进行数据绑定(databinding)比较直观方便,可以帮助我们自动生成一些必要的代码。

我们以一个Text文本框为例,来说明如果将一个文本框的内容与一个POJO对象中的属性进行绑定。

如下图,一个简单对话框中有一个Text文本框,

鼠标右键点击文本框,选择绑定功能(Bindings),然后选择Text的text属性,也就是保存Text文本框文本内容的属性。

然后会出现这样的界面,让我们选择要绑定的数据对象,在本例中数据对象的类型是TestBinding.Configurtion,变量名是editorConfig,要绑定的属性是globalAspectRatio(看这个变量名,你应该能猜到这是个浮点型数据,这就引出了后面的数据类型转换)

然后会显示绑定的细节属性,这里我们都使用默认值,所以点击确定就好了

这样一个简单的数据绑定就完成了。

数据转换和数据验证

如果数据挷定的两个对象属性的类型是一样,那上面的工作就算完成了。

但如果类型不同,就需要涉及到数据类型转换和数据验证的技术了。

jface databinding提供了两个基本的接口用于数据类型转换和数据验证

分别是IConverter和IValidator。

对于基本的数据类型转换,jface已经提供了IConverter接口的实现:

StringToNumberConverter类用于将String转换成数值(Float,Double,Integer,Long,BigDecimal…) NumberToStringConverter类用于将数值转换成String

而IValidator则需要根据实际需求自己来写。

下面的代码实现了Float类型的属性与Text组件之间的数据绑定,这其中用到了StringToNumberConverter进行数据类型转换。同时用IValidator实现数据的合法性验证。

TestBinding.java

代码语言:javascript
复制
package testwb;

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.SWT;
import org.eclipse.swt.widgets.Text;

import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.core.databinding.beans.PojoProperties;
import org.eclipse.core.databinding.conversion.StringToNumberConverter;
import org.eclipse.swt.widgets.Display;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport;
import org.eclipse.jface.databinding.swt.DisplayRealm;

public class TestBinding extends Dialog {
    /**
     * 数据对象定义
     * @author guyadong
     *
     */
    public class Configuration {
        private Float globalAspectRatio;

        public Float getGlobalAspectRatio() {
            return globalAspectRatio;
        }

        public void setGlobalAspectRatio(Float globalAspectRatio) {
            this.globalAspectRatio = globalAspectRatio;
            System.out.printf("updated %f\n",globalAspectRatio);
        }

        public Configuration(Float globalAspectRatio) {
            super();
            this.globalAspectRatio = globalAspectRatio;
        }
    }
    private DataBindingContext m_bindingContext;
    /**
     * 成员变量:数据对象
     */
    protected Configuration editorConfig=new Configuration(0.5f);
    /**
     * Text组件
     */
    private Text globalAspectRatioValue;

    /**
     * Create the dialog.
     * @param parentShell
     */
    public TestBinding(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);
        globalAspectRatioValue = new Text(container, SWT.BORDER);
        globalAspectRatioValue.setBounds(38, 28, 73, 23);

        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(362, 298);
    }
    @Override
    protected void configureShell(Shell newShell) {
        newShell.setText("设置");  
        super.configureShell(newShell);
    }
    public static void main(String[] args) {
        Display display = Display.getDefault();
        Realm.runWithDefault(DisplayRealm.getRealm(display), new Runnable() {
            public void run() {
                try {
                    TestBinding setting = new TestBinding(null);
                    setting.open();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    protected DataBindingContext initDataBindings() {
        DataBindingContext bindingContext = new DataBindingContext();
        IObservableValue observeTextGlobalAspectRatioValueObserveWidget = WidgetProperties.text(SWT.Modify).observe(globalAspectRatioValue);
        IObservableValue globalAspectRatioEditorConfigObserveValue = PojoProperties.value("globalAspectRatio").observe(editorConfig);
        // 创建String 到 Float的转换器
        StringToNumberConverter converter = StringToNumberConverter.toFloat(false);
        // 更新策略对象(Text内容改变时更新)
        UpdateValueStrategy updateStrategy = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE).setConverter(converter);
        // 设置Set方法验证器(Set方法修改Text文本内容之前验证)
        // Lambda表达式实现,验证失败返回错误信息
        updateStrategy.setBeforeSetValidator((value) -> {
                // 这里value的类型是数据对象的属性类型 (Float)
                if ((Float)value<100) {
                    return ValidationStatus.ok();
                }
                return ValidationStatus.error("globalAspectRatio must <100");
        });
        // 设置Get方法验证器(Get方法获取Text文本内容之后验证)
        // 传统匿名类实现,验证失败返回错误信息
        updateStrategy.setAfterGetValidator(new IValidator() {
            @Override
            public IStatus validate(Object value) {         
                // 这里value的类型是Text对象的text属性类型(String)   
                boolean ok=false;
                try{
                    Float s = (Float) converter.convert(value);
                    if (s<100) {
                        ok=true;
                        return ValidationStatus.ok();
                    }
                    return ValidationStatus.error("globalAspectRatio must <100");
                }catch(Exception e){
                    return ValidationStatus.error("无效数字");
                }finally{
                    // 数据无效时 disable OK按钮
                    getButton(IDialogConstants.OK_ID).setEnabled(ok);
                }}
        });
        // 调用bindValue完成Text.text到数据对象的globalAspectRatio属性的绑定
        Binding bindValue = bindingContext.bindValue(observeTextGlobalAspectRatioValueObserveWidget, globalAspectRatioEditorConfigObserveValue, 
                updateStrategy,
                null);
        // 创建错误提示组件,当验证失败时显示提示信息
        ControlDecorationSupport.create(bindValue, SWT.TOP | SWT.LEFT);
        return bindingContext;
    }
}

如下图运行程序,当输入无效字符时,Text左上角会显示出错的红X,鼠标移动到X上会显示我们的验证器(IValidator)返回的错误信息。

这是由这行代码ControlDecorationSupport.create(bindValue, SWT.TOP | SWT.LEFT);创建的ControlDecorationSupport对象实现的

当验证失败,数据对象的绑定属性不会被更新。

说明:

本例中只是实现了Text组件向Configuration类的Float类型属性的单向数据同步。事实上jface databinding可以实现双向数据同步。

参考资料:

《AJFace Data Binding - Tutorial》

《JFace Data Binding》

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年12月22日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • WindowBuilder下数据绑定操作
  • 数据转换和数据验证
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档