jface databinding:延迟计算--ComputedValue和WritableList使用的例子
2016-12-21 15:06
615 查看
ComputedValue
org.eclipse.core.databinding.observable.value.ComputedValue<T>类实现IObservableValue接口,提供对象T的延迟计算特性,它提供了一个抽象方法calculate,实现这个方法就可以实现根据多个可监控对象(IObservableValue)计算更新当前对象的需求。
尼玛,好抽象,我自己都不知道在说什么,还是举个例子吧。
比如我们有一张表
List<Integer>,这张表中的元素会被修改(添加,删除,更新)。
另外一个值
sum,sum是上面这张表所有元素的和。所以如果要获取sum的值,就要对List进行求和。
下面这段代码通过实现
ComputedValue<Integer>的抽象方法calculate来完成sum的自动求和功能,println方法调用sum的getValue时会自动计算List中的所有元素的总和。
TestComputeValue.java
package testwb; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.core.databinding.observable.Realm; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.list.WritableList; import org.eclipse.core.databinding.observable.value.ComputedValue; import org.eclipse.jface.databinding.swt.DisplayRealm; import org.eclipse.swt.widgets.Display; public class TestComputeValue { public static void main(String[] args) { Display display = Display.getDefault(); Realm realm = DisplayRealm.getRealm(display); // 创建一张空表 final IObservableList<Integer> addends = new WritableList<Integer>(realm); // 向表中添加元素 addends.add(Integer.valueOf(0)); addends.add(Integer.valueOf(1)); addends.add(Integer.valueOf(2)); // 定义sum,实现calculate方法完成自动求和计算 ComputedValue<Integer> sum = new ComputedValue<Integer>() { protected Integer calculate() { int sum = 0; for (Iterator<Integer> it = addends.iterator(); it.hasNext();) { Integer addend = (Integer) it.next(); sum += addend.intValue(); } // 返回求和结果 return sum; } }; // 输出sum,通过getValue获取sum时,已经自动调用calculate方法计算了List总和 System.out.println(sum.getValue()); // => 3 // 向表中动态增加一个元素,则再次输出sum的值时,已经更新 addends.add(Integer.valueOf(10)); System.out.println(sum.getValue()); // => 13 } }
WritableList
这里要说明一下上面例子中的另一个主角WritableList,WritableList其实就是一个List,并且它实现了IObservableList接口(监控表中所有元素接口),所以可以对List中的所有元素进行监控。我们可以将任何一个普通的
java.util.List封装成WritableList以实现对表中所有元素的监控,所以上面的示例代码也可以写成这样:
TestComputeValue2.java
package testwb; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.core.databinding.observable.Realm; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.list.WritableList; import org.eclipse.core.databinding.observable.value.ComputedValue; import org.eclipse.jface.databinding.swt.DisplayRealm; import org.eclipse.swt.widgets.Display; public class TestComputeValue2 { public static void main(String[] args) { Display display = Display.getDefault(); Realm realm = DisplayRealm.getRealm(display); //构造一个List,并添加元素。 List<Integer> list = new ArrayList<Integer>(); list.add(0); list.add(1); list.add(2); // 构造WritableList对象将list封装成IObservableList final IObservableList<Integer> addends = new WritableList<Integer>(realm,list,null); ComputedValue<Integer> sum = new ComputedValue<Integer>(realm) { protected Integer calculate() { int sum = 0; for (Iterator<Integer> it = addends.iterator(); it.hasNext();) { Integer addend = (Integer) it.next(); sum += addend.intValue(); } return sum; } }; System.out.println(sum.getValue()); // => 3 addends.add(Integer.valueOf(10)); System.out.println(sum.getValue()); // => 13 System.out.println(list.size());// list中元素数目更新了,变为4, } }
runWithDefault
其实这个例子是我从ComputedValue源代码注释中抄来的(参见ComputedValue),只是注释中的example代码并不完整,而且还写错了(WritableList.withElementType写成了
WritableValue.withValueType)。在修改这段代码的时候,总算算搞清楚了ComputedValue的玩儿法。
看到这时你也许会问,既然ComputedValue源码中的例子错将
WritableList.withElementType写成了
WritableValue.withValueType,你上面的代码中为什么没有用
WritableList.withElementType方法来构造WritableList对象呢?
用withElementType静态方法来构造WritableList的确很方便,但它是有环境使用要求的。请看它的代码:
public static <T> WritableList<T> withElementType(Object elementType) { return new WritableList<T>(Realm.getDefault(), new ArrayList<T>(), elementType); }
在调用构造函数
WritableList(Realm realm, List<E> toWrap, Object elementType)时对于第一个realm参数是用
Realm.getDefault()静态方法获取的。而默认情况下
Realm.getDefault()返回是null(why?参见Realm代码),所以使用withElementType静态方法肯定就抛出异常了。
那么什么情况下Realm.getDefault()返回不为null呢?
看下面Realm中的runWithDefault静态方法的代码就明白了:
public static void runWithDefault(Realm realm, Runnable runnable) { Realm oldRealm = Realm.getDefault(); try { //设置defaultRealm,只有这时defaultRealm的值才不为null defaultRealm.set(realm); // 执行Runnable对象 runnable.run(); } finally { // 执行完后恢复defaultRealm defaultRealm.set(oldRealm); } }
所以如果要像ComputedValue源码中的例子那样使用withElementType静态方法来构造WritableList,代码应该这样写:
TestComputeValue3.java
package testwb; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.core.databinding.observable.Realm; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.list.WritableList; import org.eclipse.core.databinding.observable.value.ComputedValue; import org.eclipse.jface.databinding.swt.DisplayRealm; import org.eclipse.swt.widgets.Display; public class TestComputeValue3 { public static void main(String[] args) { Display display = Display.getDefault(); Realm.runWithDefault(DisplayRealm.getRealm(display), new Runnable() { public void run() { try { // 调用withElementType静态方法创建WritableList对象 final IObservableList<Integer> addends = WritableList.withElementType(null); addends.add(Integer.valueOf(0)); addends.add(Integer.valueOf(1)); addends.add(Integer.valueOf(2)); ComputedValue<Integer> sum = new ComputedValue<Integer>() { protected Integer calculate() { int sum = 0; for (Iterator<Integer> it = addends.iterator(); it.hasNext();) { Integer addend = (Integer) it.next(); sum += addend.intValue(); } return sum; } }; System.out.println(sum.getValue()); // => 3 addends.add(Integer.valueOf(10)); System.out.println(sum.getValue()); // => 13 } catch (Exception e) { e.printStackTrace(); } } }); } }
lambda支持
Eclipse Neon版本中ComputedValue类增加了一个新的create静态方法,来创建ComputedValue对象,create方法允许更方便的使用lamda表达来实现calculate方法。例如下面的代码:
IObservableValue<String> lastName = // ... IObservableValue<String> firstName = // ... // 调用create方法通过lambda表达式作为calculate方法的实现 IObservableValue<String> formattedName = ComputedValue.create(() -> { String lastNameValue = lastName.getValue(); String firstNameValue = firstName.getValue(); return lastNameValue + "," + firstNameValue; });
参考:
ComputedValue
AJFace Data Binding - Tutorial
相关文章推荐
- jface databinding:重写doSetValue方法ComputedValue实现双向多对一的数据绑定
- 8.6.1 例子:使用First_value来计算最大值
- jface databinding:List,Set,Map对象的Observable代理封装
- jface databinding: Radio Button group及ISideEffect绑定数据对象的例子
- 2.4 The Object Model -- Computed Properties and Aggregate Data with @each(计算的属性和使用@each聚合数据)
- jface databinding:UpdateValueStrategy(数值更新策略)类详解
- jface databinding:可多选的widget List组件selection项目与java.util.List对象的双向数据绑定
- jface databinding:使用CheckboxTableViewer实现表中(Set)对象与CheckTable中选中条目数据绑定
- JFace DataBinding 中的 MultiValidator学习和体会
- 使用类型化DataSet时,通过延迟DataTable的Expression列计算来提高Fill的性能
- Silverlight入门教程(五): 使用ListBox and DataBinding 组件显示列表数据-教程资料网 www.zhiweinet.com
- TValueListEditor的使用
- C#中关于在List集合类中使用泛型的例子
- sourcegrid 应用实例(全部来自官网下载的例子)——Advanced Data Binding - DataGrid, alternate backcolor
- [Windows Forms] : BindingSource使用模式 - Data Binding基础知识 (一)
- sourcegrid 应用实例(全部来自官网下载的例子)——Advanced Data Binding - different Views, images and tooltip
- sourcegrid 应用实例(全部来自官网下载的例子)——Advanced Data Binding - DataGrid 3, validation rules
- How to bind a GridView to a list of multiple types? NHibernate proxy causing problems with databinding [From stack overflow]
- 关于柯老师的延迟计算例子
- WM_COPYDATA使用例子