PropertyChangeSupport的使用,有这么几个类是相关的PropertyChangeEvent、PropertyChangeListener;
看一个小的例子:
public class A_listViewerExample {
public static void main(String[] args) {
Display display = Display.getDefault();
Shell shell = new Shell(display);
shell.setSize(400, 400);
shell.setLayout(new FillLayout());
ListViewer viewer = new ListViewer(shell, SWT.BORDER);
viewer.setLabelProvider(new LabelProvider());
viewer.setContentProvider(new ContentProvider());
viewer.setInput(getData());
((ListModel)viewer.getInput()).printInfo();
shell.open();
viewer.add(new UserModel("3","Ascos"));
((ListModel)viewer.getInput()).add(new UserModel("4","Jack"));
((ListModel)viewer.getInput()).printInfo();
// viewer.refresh();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
}
private static Object getData() {
ListModel input = new ListModel();
input.add(new UserModel("1","Chris"));
input.add(new UserModel("2","Leon"));
return input;
}
}
class LabelProvider implements ILabelProvider {
public Image getImage(Object element) {
return Display.getCurrent().getSystemImage(SWT.ICON_WORKING);
}
public String getText(Object element) {
if(element instanceof UserModel)
return ((UserModel)element).getName();
return element.toString();
}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void dispose() {}
public void addListener(ILabelProviderListener listener) {}
public void removeListener(ILabelProviderListener listener) {}
}
class ContentProvider implements IStructuredContentProvider, PropertyChangeListener {
private ListViewer viewer;
public Object[] getElements(Object inputElement) {
if(inputElement instanceof ListModel)
return ((ListModel)inputElement).elements();
return null;
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
this.viewer = (ListViewer) viewer;
if (oldInput instanceof ListModel)
((ListModel) oldInput).removePropertyChangeListener(this);
if (newInput instanceof ListModel)
((ListModel) newInput).addPropertyChangeListener(this);
}
public void propertyChange(PropertyChangeEvent event) {
if(event.getPropertyName().equals(ListModel.ADD_ELEMENT))
viewer.add(event.getNewValue());
if(event.getPropertyName().equals(ListModel.REMOVE_ELEMENT))
viewer.remove(event.getNewValue());
}
public void dispose() {}
}
class ListModel {
public static final String ADD_ELEMENT = "add Element";
public static final String REMOVE_ELEMENT = "remove Element";
private PropertyChangeSupport delegate;
private Vector<Object> content;
public ListModel() {
content = new Vector<Object>();
delegate = new PropertyChangeSupport(this);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
delegate.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
delegate.removePropertyChangeListener(listener);
}
public void firePropertyChange(PropertyChangeEvent event) {
delegate.firePropertyChange(event);
}
public void add(Object element) {
if (content.add(element))
firePropertyChange(new PropertyChangeEvent(this, ADD_ELEMENT, null, element));
}
public void remove(Object element) {
if (content.remove(element))
firePropertyChange(new PropertyChangeEvent(this, REMOVE_ELEMENT, null, element));
}
public Object[] elements() {
return content.toArray();
}
public void printInfo() {
for(Object o : content) {
if(o instanceof UserModel) {
UserModel user = (UserModel)o;
System.out.println("The user id is "+user.getId() + ", and name is " + user.getName());
}
}
}
}
class UserModel {
private String id;
private String name;
public UserModel(String id, String name) {
this.id = id;
this.name = name;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
一个简单的Jface的ListViewer的例子,这是一个PropertyChangeSupport的典型的在GUI的中的应用,在GUI中有一个普遍的问题,就是数据和图形同步的问题,如上面的例子ListViewer,【viewer.add(new UserModel("3","Ascos"));】这个就是仅仅在图像中的增加了数据项,而在对应的数据原型上面listModel上面根本没有增加数据项,这个带来了一个问题,就是图形显示的和底层数据的不一致的问题,这样的话,要是GUI一但刷新的画,就会出现问题了,应该通常的数据刷新都是GUI根据底层数据来刷新,就发现刷新完的GUI数据项“Ascos”不见了。上面的例子,可以将【viewer.refresh();】这个注释的语句打开就可以测试一下。
为了保持数据和GUI的同步,只有Data.add同时View.add,还要Data.remove的同时View.remove;这个办法能够解决上面的数据和GUI显示同步的问题,但是对于后期的维护和功能的扩展是非常不方便的,如考虑GUI的常常出现的一种扩展的需求,如上面的List的例子,现在老板觉得是不是table的显示或者tree或者tabletree或者graphics的显示是不是更好一些呢,于是有了view1、view2、view3、在没有一个数据add的地方,加上对view的add,remove的地方也是。这样的修改,常常出现遗漏和错误。
应该PropertyChangeSupport,就可以解决上面的问题,数据看成是属性的提供方,所有的view都看着做是,这个属性的监听方,这样不管你加入多少的view,在创建view的时候,就注册到属性提供方中去,然后数据的变化就会。
其实,这个也很好的实现了GUI中的基本思想就MVC的思想,M就是基本的数据单元,V就是各种View,C就是逻辑业务单元的处理,这个负责M的创建也就是Data的创建,增加,删除等操作,V自动对应到Data模型,是多么完美的事情啊。
不过,这种属性监听的模式,和观察者的模式,非常的相似,观察者=监听者;被观察者=背监听者=管理者;