【插件開發】—— 11 竊聽風雲(Java事件監聽原理-GEF實例講解)


前文回顧:

插件學習篇

簡單的建立插件工程以及模型文件分析

利用擴展點,開發透視圖

SWT編程須知

SWT簡單控件的使用與布局搭配

SWT復雜空間與布局搭配

SWT布局詳解

IPreferenceStore使用詳解

編輯器代碼着色

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();
   ... 
 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM