1 介绍
1.1 Jface数据绑定
Jface数据绑定主要用于Eclipse的插件开发。例如,你可以绑定一个类的特定属性:’姓名‘ 至SWT的Text控件中。此时如果用户改变控件中的值,对象中的特定属性随之改变。
1.2 通过listener对改变进行响应
为了可以对java对象里属性的变化进行相应,Jface 数据绑定 需要将自己注册为特定属性的listener。 SWT和Jface支持这项操作。
Jface数据绑定同样可以用来检测领域模型(
domain model)中特定属性的变化。
2 创建Jface 数据绑定
2.1 Java POJO 和Java Bean
Java中的数据模型通常以Java Plain Old Java Object (POJO) 模型 或者 Java Bean 模型定义(在MVC基础上)。
POJO是一种普通的Java对象。它包含业务逻辑或持久逻辑等,但不是JavaBean、EntityBean。其相对于javabean,没有那么严格的要求。
下面是一个POJO的例子:
package de.vogella.databinding.example;
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
JavaBean的声明遵循一定的规则,包含getter/sitter(针对每一个属性),公有默认构造函数,可序列化等等。
下面是一个javabean的例子(包含
PropertyChangeSupport
):
package de.vogella.databinding.example;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class ModelObject {
private PropertyChangeSupport changeSupport =
new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener
listener) {
changeSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener
listener) {
changeSupport.removePropertyChangeListener(listener);
}
public void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
changeSupport.addPropertyChangeListener(propertyName, listener);
}
public void removePropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
changeSupport.removePropertyChangeListener(propertyName, listener);
}
protected void firePropertyChange(String propertyName,
Object oldValue,
Object newValue) {
changeSupport.firePropertyChange(propertyName, oldValue, newValue);
}
}
其他类可以继承这个类:
package de.vogella.databinding.example;
public class Person extends ModelObject {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
firePropertyChange("name", this.name, this.name = name);
}
}
2.2 POJO的数据绑定
POJO支持数据绑定,但是不支持变动通知(change notification)。所以POJO里的改变无法反映到用户界面上。但是用户界面上的改动可以反映到POJO中来。
2.3 Observable
绑定任意属性,需要用到java提供的observe方法。不同数据模型需要使用相应的工厂类:
Java提供了三种工厂类:
Factory | Description |
---|---|
PojoProperties | Used to create IObservableValues for Java objects. |
BeanProperties | Used to create IObservableValue objects for Java Beans. |
WidgetProperties | Used to create IObservableValues for properties of SWT widgets. |
2.4 观察属性变化
数据模型
// if person is a POJO
IObservableValue myModel = PojoProperties.value("firstName").
observe(person)
// alternatively if person is a bean use
// prefer using beans if you data model provides property change support
IObservableValue myModel = BeansProperties.value("firstName").
observe(person)
SWT:
IObservableValue target = WidgetProperties.text(SWT.Modify).
observe(firstNameText);
成员变量的属性:比如我们需要绑定person类中adress属性下的country属性
IObservable model = PojoProperties.value(Person.class,
"address.country").observe(person);
2.5 正文(context)数据绑定
DataBindingContext类允许对IObservableValues的对象进行连接/绑定。通过DataBindingContext类中bindValue方法,我们可以将两个IObservableValues的对象连接起来。第一个参数是目标对象,第二个参数是数据模型。在初始化阶段,数据模型会被复制到目标对象中去。
// create new Context
DataBindingContext ctx = new DataBindingContext();
// define the IObservables
IObservableValue target = WidgetProperties.text(SWT.Modify).
observe(firstName);
IObservableValue model= BeanProperties.
value(Person.class,"firstName").observe(person);
// connect them
ctx.bindValue(target, model);
3 JFace plugins的数据绑定
在plugins的依赖中加入下列包即可:
-
org.eclipse.core.databinding
-
org.eclipse.core.databinding.beans
-
org.eclipse.core.databinding.property
-
org.eclipse.jface.databinding
4 补充
4.1 UpdateValueStrategy
bindValue方法的第三,四个选择性形参允许用户定义自己的UpdateValueStrategy。目的是允许用户定义同步的方法。
4.2 converter 和 validator
Validator允许用户在同步进行之前进行验证,而converter允许用户在目标与数据模型之间进行转换。
// define a validator to check that only numbers are entered
IValidator validator = new IValidator() {
@Override
public IStatus validate(Object value) {
if (value instanceof Integer) {
if (value.toString().matches(".*\\d.*")) {
return ValidationStatus.ok();
}
}
return ValidationStatus.error(value.toString() +"is not a number");
}
};
// create UpdateValueStrategy and assign
// to the binding
UpdateValueStrategy strategy = new UpdateValueStrategy();
strategy.setBeforeSetValidator(validator);
Binding bindValue =
ctx.bindValue(widgetValue, modelValue, strategy, null);
4.3 ControlDecorators
JFace数据绑定允许用户使用Decorator对数据输入进行实时响应。
比如:

// The following code assumes that a Validator is already defined
Binding bindValue =
ctx.bindValue(widgetValue, modelValue, strategy, null);
// add some decorations to the control
ControlDecorationSupport.create(bindValue, SWT.TOP | SWT.LEFT);
5 JFace Viewer 数据绑定
5.1 Viewer绑定
Viewer的数据绑定需要对input进行区分,针对collection和单独对象,需要进行不同的处理。
比如,针对一个collection,我们需要用contentProvider对数据的改变发出通知。例如ObservableListContentProvider类,它继承了contentProvider并且实现了IObservableList接口。Properties类允许用户使用selfList方法对用户提供的list进行封装。
// use ObservableListContentProvider
viewer.setContentProvider(new ObservableListContentProvider());
// create sample data
List<Person> persons = createExampleData();
// wrap the input into a writable list
IObservableList input =
Properties.selfList(Person.class).observe(persons);
// set the IObservableList as input for the viewer
viewer.setInput(input);
5.2 观察list的成员
如果需要观测list的成员,我们可以用ObservableMapLabelProvider类。
ObservableListContentProvider contentProvider =
new ObservableListContentProvider();
// create the label provider including monitoring
// of the changes of the labels
IObservableSet knownElements = contentProvider.getKnownElements();
final IObservableMap firstNames = BeanProperties.value(Person.class,
"firstName").observeDetail(knownElements);
final IObservableMap lastNames = BeanProperties.value(Person.class,
"lastName").observeDetail(knownElements);
IObservableMap[] labelMaps = { firstNames, lastNames };
ILabelProvider labelProvider =
new ObservableMapLabelProvider(labelMaps) {
public String getText(Object element) {
return firstNames.get(element) + " " + lastNames.get(element);
}
};
5.3 viewerSupport
如果list中对象的所有属性均需要显示出来,我们可以使用viewerSupport。viewerSupport会自己负责创建contentProvider和labelProvier。这样使用起来更方便。
// the MyModel.getPersons() method call returns a List<Person> object
// the WritableList object wraps this object in an IObservableList
input = new WritableList(MyModel.getPersons(), Person.class);
// The following creates and binds the data
// for the Table based on the provided input
// no additional label provider /
// content provider / setInput required
ViewerSupport.bind(viewer, input,
BeanProperties.
values(new String[] { "firstName", "lastName", "married" }));
5.4 Master/Detail 模式数据绑定
// assume we have Todo domain objects
// todos is a of type: List<Todo>
final ComboViewer viewer = new ComboViewer(parent, SWT.DROP_DOWN);
viewer.setContentProvider(ArrayContentProvider.getInstance());
viewer.setLabelProvider(new LabelProvider() {
public String getText(Object element) {
Todo todo = (Todo) element;
return todo.getSummary();
};
});
viewer.setInput(todos);
// create a Label to map to
Label label = new Label(parent, SWT.BORDER);
// parent has a GridLayout assigned
label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
DataBindingContext dbc = new DataBindingContext();
// for binding to the label
IObservableValue target = WidgetProperties.text().observe(label);
// observe the selection
IViewerObservableValue selectedTodo = ViewerProperties
.singleSelection().observe(viewer);
// observe the summary attribute of the selection
IObservableValue detailValue =
PojoProperties
.value("summary", String.class)
.observeDetail(selectedTodo)
dbc.bindValue(target, detailValue);
5.5 Chaining properties
IObservableValue viewerSelectionSummaryObservable =
ViewerProperties.singleSelection()
.value(BeanProperties.value("summary", String.class))
.observe(viewer);
IListProperty siblingNames = BeanProperties.
value("parent").list("children").values("name");
IObservableList siblingNamesObservable =
siblingNames.observe(node);