jface databinding:输入无效数值时强制恢复初始值-updateModelToTarget

解决方案

Binding类中的updateModelToTarget方法,就是实现从数据对象到目标对象(比如Widget)的更新方法,只要调用这个方法就能强制让数据对象的内容同步到目标对象。如下是抽象方法updateModelToTarget的说明:

    /**
     * Updates the target's state from the model's state at the next reasonable
     * opportunity. There is no guarantee that the state will have been updated
     * by the time this call returns.
     * 在合适的机会将model状态更新到target,因为是异步更新,所以不保证当方法返回时target更新完成。
     */
    public abstract void updateModelToTarget();

问题描述

如下代码显示一个简单的对话框,Text文本框中初始是个浮点数0.5,当修改文本框中的内容不符合float数值格式时,左上角会提示出错。点击下面的”恢复初始值”按钮,希望能恢复初始值0.5。

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.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.jface.databinding.swt.WidgetProperties;
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;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;

public class TestPojoBinding5 extends Dialog {

    private DataBindingContext m_bindingContext;
    // floatValue 初始值0.5f
    private final WritableValue<Float> floatValue = new WritableValue<Float>(Float.valueOf(0.5f), Float.class);
    // Text文本框对象
    private Text floatValueText;
    private Binding bindValue;

    /**
     * Create the dialog.
     * @param parentShell
     */
    public TestPojoBinding5(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);

        Button btnNewButton = new Button(container, SWT.NONE);
        // 点击“恢复初始值”按钮时,将floatValue重新设置为初始值
        btnNewButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                floatValue.setValue(Float.valueOf(0.5f));
            }
        });
        btnNewButton.setBounds(38, 154, 80, 27);
        btnNewButton.setText("恢复初始值");

        floatValueText = new Text(container, SWT.BORDER);
        floatValueText.setBounds(38, 27, 80, 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);
    }
    public static void main(String[] args) {
        Display display = Display.getDefault();
        Realm.runWithDefault(DisplayRealm.getRealm(display), new Runnable() {
            public void run() {
                try {
                    TestPojoBinding5 setting = new TestPojoBinding5(null);
                    setting.open();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    protected DataBindingContext initDataBindings() {
        DataBindingContext bindingContext = new DataBindingContext();
        //
        IObservableValue observeTextFloatValueTextObserveWidget = WidgetProperties.text(SWT.Modify).observe(floatValueText);
        // 将floatValueText和floatValue进行数据绑定
        bindValue=bindingContext.bindValue(observeTextFloatValueTextObserveWidget, floatValue, null, null);
        // 创建验证错误提示组件(就是Text文本框左上角的红X号,数据验证出错时显示),
        ControlDecorationSupport.create(bindValue, SWT.TOP | SWT.LEFT);
        return bindingContext;
    }
}

实际的结果是: 当修改Text文本框内容为一个合法的浮点数时,点击”恢复初始值”按钮Text显示内容的确可以恢复到初始值0.5, 但是当输入的内容无效,不是一个数字时,点击”恢复初始值”按钮也恢复不到初始值? 这是为什么呢?难道jface有bug?

问题溯源

通过跟踪代码搞清楚了原因: 假设当前Text的内容是初始值0.5,然后修改Text的内容, 不论Text文本框的内容是否为有效数字,点击”恢复初始值”按钮时,floatValue.setValue(Float.valueOf(0.5f));确实被执行了, 但区别是当输入Text文本框的内容为无效数字时,floatValue的内容并不会被修改,也就是还保持之前的值(0.5),此时再点击”恢复初始值”按钮时,设置的值还是0.5,floatValue并没有改变,所以没有触发Text的更新。 再做一个试验来验证上面的逻辑: 如果先将Text的内容从0.5改为另一个有效数字(比如0.9)—(此时floatValue被更新为0.9),然后再改为一个无效数字hello,然后点击”恢复初始值”按钮,则Text的内容正常恢复。 由此找出了问题的原因:当数据对象更新的值与原值相等时,setValue不能触发Widget组件的更新。 怎么解决呢?仔细研究了,org.eclipse.core.databinding.ValueBinding代码中的数据更新的方法doUpdate,及其调用层次结构,由此就找到了本文开始的答案。

ValueBinding继承于抽象类Binding,Binding类中的updateModelToTarget方法,就是实现从数据对象到目标对象(比如Widget)的更新方法,只要调用这个方法就能强制让数据对象的内容同步到目标对象。

修改代码

所以解决这个问题的办法很简单,如下增加一行代码即可:

        // 点击“恢复初始值”按钮时,将floatValue重新设置为初始值
        btnNewButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                floatValue.setValue(Float.valueOf(0.5f));
                // 强制更新Text组件内容
                bindValue.updateModelToTarget();
            }
        });

当然仔细想想上面这样修改的确是简单,但在Text已经被更新的情况下,会多一次强制更新的动作,所以如果代码写得更仔细点,应该是这样:

        // 点击“恢复初始值”按钮时,将floatValue重新设置为初始值
        btnNewButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                // 判断floatValue是否等于初始值(0.5f),如果是的话,只做强制更新
                if(floatValue.getValue()==0.5f)
                    bindValue.updateModelToTarget();
                else// 否则就更新floatValue,Text会自动更新。
                    floatValue.setValue(Float.valueOf(0.5f));               
            }
        });

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏偏前端工程师的驿站

Java魔法堂:finalize函数

一、finalize与GC                               在GC第一次进行可达性分析时会将不可达而且该对象所属类重写finaliz...

1726
来自专栏Gcaufy的专栏

WePY 在小程序性能调优上做出的探究

性能调优是一个亘古不变的话题,无论是在传统H5上还是小程序中。本文旨在介绍两点在小程序开发过程当中碰到的一些性能问题以及 WePY 的一些优化方案。

2.1K2
来自专栏Java帮帮-微信公众号-技术文章全总结

Java基础-day10-代码题-继承&抽象类

Java基础-day10-代码题-继承&抽象类 1.门类继承题: 编写代码,实现如下功能: (1)定义一个门类, 包含3个属性:宽度width 和 高度hei...

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

以读取博客园随笔备份为例 将xml 序列化成json,再序列化成对象

资源下载:http://files.cnblogs.com/codealone/ConsoleApplication2.zip

361
来自专栏腾讯NEXT学位

一看就晕的React事件机制

4328
来自专栏为数不多的Android技巧

Java高效分割字符串

最近优化一段代码的调用时间,发现性能瓶颈居然是io和split!io操作慢情有可原,那么对于split有没有更高效的方法呢?

942
来自专栏PHP技术

哎呦不错哦!一组让人眼前一亮的404创意页面设计

原文出处: graphicdesignjunction 译文出处:优设网 WEARESPRY – 404 Error Page ? Cayenne –...

3214
来自专栏菩提树下的杨过

Unity Application Block 1.2 学习笔记

昨天花了一天时间,把IOC/DI的相关文章以及Unity相关的一些文章基本在园子里搜了个遍 先给出几篇不错的文章链接: Unity Application Bl...

19110
来自专栏农夫安全

注入学习之sqli-labs-6(第五次)

前言 上一次课讲解的是sql基于布尔型盲注,紧接着这节讲基于时间的盲注 布尔型盲注,是在我们判断网站是否存在注入的时候,网页不会暴漏错误信息,但会返回正确的页面...

3546
来自专栏从零开始学自动化测试

Selenium2+python自动化57-捕获异常(NoSuchElementException)

前言 在定位元素的时候,经常会遇到各种异常,为什么会发生这些异常,遇到异常又该如何处理呢? 本篇通过学习selenium的exceptions模块,了解异常发生...

2994

扫码关注云+社区