【插件开发】—— 11 窃听风云(Java事件监听原理-GEF实例讲解)

前文回顾:html

插件学习篇编程

简单的创建插件工程以及模型文件分析架构

利用扩展点,开发透视图编辑器

SWT编程须知函数

SWT简单控件的使用与布局搭配布局

SWT复杂空间与布局搭配学习

SWT布局详解this

IPreferenceStore使用详解spa

编辑器代码着色插件

10 JFace开发

  事件的监听,是插件开发中的重要环节,每一次的点击或者按键都有可能触发某种事件的响应,那么是如何实现的呢?

  对于某种被监听模型,一般须要添加一个监听队列

  监听者须要经过某种方式,加入到这个监听队列中

  当这个模型在特定的状况下触发监听事件后,会产生一个事件的响应,这个响应使得监听队列中的每一个监听者都触发响应的操做

  例以下面这个小例子:

class FocusedCountry{ List<IListener> listener = new ArrayList(); public void addListener(IListener lis){ listener.add(lis); } //移除监听者
    public void removeListener(IListener lis){ listener.remove(lis); } //触发监听事件
    protected void fireChange(String message){ for(IListener lis : listener){ lis.noticedChange(message); } } }

  这个被监听的对象,有一个监听队列,全部对它感兴趣的人都会加入到这个监听队列中。所以主要有三个函数,加入到队列中,从队列离开,以及自己的一个触发函数。

interface IListener{ public void noticedChange(String message); } class DevelopedCountry implements IListener{ public void noticedChange(String message) { System.out.println("noticed the change:"+message); } }

  上面实现了一个监听的接口,只要实现了这个接口的类,均可以添加到队列中。

public class ListenTest { public static void main(String[] args) { DevelopedCountry America = new DevelopedCountry(); FocusedCountry China = new FocusedCountry(); FocusedCountry NorthKorea = new FocusedCountry(); China.addListener(America); NorthKorea.addListener(America); China.fireChange("登月!"); NorthKorea.fireChange("原子弹造好了,该去哪扔呢!"); } }

  调用结果以下,全部的事件都被监听者接收到了。

noticed the change:登月! noticed the change:原子弹造好了,该去哪扔呢!

 

  那么GEF中是如何使用的呢?

  GEF是一种MVC标准的架构,它的模型负责实现这个监听队列,而Control负责接收监听,进行响应,从而改变View的模型

  所以,通常的Model都会继承一个自定义的虚类,这个虚类中包含了一个监听队列,以及上面提到的三种函数。

public class AbstractModel implements Serializable{ private PropertyChangeSupport listeners = new PropertyChangeSupport(this); public void addPropertyChangeListener(PropertyChangeListener listener) { listeners.addPropertyChangeListener(listener); } public void firePropertyChange(String propName, Object oldValue,Object newValue) { listeners.firePropertyChange(propName, oldValue, newValue); } public void removePropertyChangeListener(PropertyChangeListener listener) { listeners.removePropertyChangeListener(listener); } }

  继承这个类后,须要某些事件进行触发监听,通常状况下,模型都会对应一些属性视图,属性视图须要继承IPropertySource接口。并重写下面的方法。

public IPropertyDescriptor[] getPropertyDescriptors() { return new IPropertyDescriptor[] { new PropertyDescriptor(P_TABLE_NAME, "table_name"), } public Object getPropertyValue(Object id) { if (id == P_TABLE_NAME) { return getPhysicalName(); } return null; } public boolean isPropertySet(Object id) { if (id == P_TABLE_NAME) { return true; } return false; } public void setPropertyValue(Object id, Object value) { if (id == P_TABLE_NAME) { seName((String) value); } }

  属性视图上的属性发生改变时,通常是在Set值的时候会触发这个firechange,最后触发到listners里面的firePropertyChange函数。

public void setXXXlName(String xxxName) { this.xxxName = xxxName; firePropertyChange(P_XXX_NAME, null, xxxName); }

  这里是一个插件开发遗留的习惯,就是会把每个事件使用一个static的字符串进行标记。函数会产生一个PropertyChange的事件。

  这样模型部分的监听就搞定了,下面要进行的是监听者的添加了。

  这里监听者须要实现PropertyChangeListener接口,并在适合的时机添加到监听队列中,因为这部分的代码在Editpart中,GEF的每个Editpart都对应了一个Model,所以经过简单的getModel方法就能够获取它对应的模型对象,再调用模型对象的addListener等方法添加到监听队列中就OK了。

public void activate() { if (isActive()) { return; } super.activate(); ((TableModel) getModel()).addPropertyChangeListener(this); } public void deactive() { if (!isActive()) { return; } super.deactivate(); ((TableModel) getModel()).removePropertyChangeListener(this); }

  通常来讲都是在这两个函数内,由于这两个函数至关于处于 通常函数的 构造函数 和 析构函数的 执行位置。

  添加完监听队列,须要实现一下PropertyChangeListener里面的PropertyChange方法,这个方法传递一个参数,经过这个参数能够获取上面最开始设定的字符串,从而判断是模型的哪一个时间发生了响应。

public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(TableModel.P_TABLE_NAME)) refreshVisuals(); ... }
相关文章
相关标签/搜索