程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> [Eclipse]GEF入門系列(十二、自定義Request)

[Eclipse]GEF入門系列(十二、自定義Request)

編輯:關於JAVA

先簡單回顧一下Request在GEF裡的作用。Request是GEF裡一個比較重要的角色,Tool將原 始的鼠標事件轉換為EditPart可以識別的請求,Request則承載了這些請求信息。舉例來說, 用戶在調色板(Palette)裡選擇了創建節點工具(CreationTool),然後在畫布區域按下鼠 標左鍵,這時產生在畫布上的鼠標單擊事件將被CreationTool轉換為一個CreateRequest,它 裡面包含了要創建的對象,坐標位置等信息。 EditPart上如果安裝了能夠處理 CreateRequest的EditPolicy,則相應的EditPolicy會根據這個 CreateRequest創建一個 Command,由後者實際執行創建新對象的必要操作。

GEF已經為我們提供了很多種類的Request,其中最常用的是CreateRequest及其子類 CreateConnectionRequest,其他比較常見的還有SelectionRequest,ChangeBoundsRequest 和 ReconnectRequest等等。要實現一個典型的圖形化應用程序,例如UML類圖編輯器,這些 預定義的Request基本夠用了。然而各種稀奇古怪的需求我相信大家也見過不少,很多需求不 太符合約定俗成的使用習慣,因此實現起來更多依賴開發人員的編碼,而不是開發框架帶來 的便利。在這種時候,我們唯一的期望就是開發框架提供足夠的擴展機制,以便讓我們額外 編寫的代碼能和其他代碼和平共處,幸好GEF是具有足夠的擴展性的。有點跑題了,再回到 Request的問題上,為了說明什麼情況下需要自定義 Request,我在前文“應用實例”裡的示 例應用基礎上假設一個新的需求:

在Palette裡增加三個工具,作用分別是把選中節點的背景顏色改變為紅色、綠色和藍色 。

假如你用過Photoshop或類似軟件,這個需求很像給節點上色的“油漆桶”或“上色工具 ”,當然在用戶界面的背後,實際應用裡這些顏色可能代表一個節點的重要程度,優先級或 是異常信息等等。現在,讓我們通過創建一個自定義的Request來實現這個需求,還是以前文 中的示例項目為基礎。

一、首先,原來的模型裡節點(Node)類裡沒有反映顏色的成員變量,所以先要在Node類 裡添加一個color屬性,以及相應的 getter/setter方法,注意這個setter方法裡要和其他成 員變量的setter方法一樣傳遞模型改變的消息。仿照其他成員變量,還應該有一個靜態字符 串變量,用來區分消息對應哪個屬性。

final public static String PROP_COLOR = "COLOR";

protected RGB color = new RGB(255, 255, 255);

public RGB getColor() {
   return color;
}

public void setColor(RGB color) {
   if (this.color.equals(color)) {
     return;
   }
   this.color = color;
   firePropertyChange(PROP_COLOR, null, color);
}

二、然後,要讓Node的color屬性變化能夠反映到圖形上,因此要修改NodePart裡的 propertyChanged()和 refreshVisuals()方法,在前者裡增加對color屬性的響應,在後者裡 將NodeFigure的背景顏色設置為Node的color屬性對應的顏色。(注意,Color對象是系統資 源對象,實際使用裡需要緩存以避免系統資源耗盡,為節約篇幅起見,示例代碼直接new Color()了)

public void propertyChange(PropertyChangeEvent evt) {

   if (evt.getPropertyName().equals(Node.PROP_COLOR))//Response to color change
     refreshVisuals();
}

protected void refreshVisuals() {

   ((NodeFigure) this.getFigure()).setBackgroundColor(new Color(null, node.getColor()));//TODO cache color instances
}

三、現在來創建我們自己的Request,因為目的是改變顏色,所以不妨叫做 ChangeColorRequest。它應當繼承自org.eclipse.gef.Request,我們需要 ChangeColorRequest上帶有兩樣信息:1.需要改變顏色的節點;2.目標顏色。因此它應該有 這兩個成員變量。

import org.eclipse.gef.Request;
import org.eclipse.swt.graphics.RGB;
import com.example.model.Node;

public class ChangeColorRequest extends Request{
   final static public String REQ_CHANGE_COLOR="REQ_CHANGE_COLOR";
   private Node node;
   private RGB color;

   public ChangeColorRequest(Node node, RGB color) {
     super();
     this.color = color;
     this.node = node;
     setType(REQ_CHANGE_COLOR);
   }

   public RGB getColor() {
     return color;
   }

   public Node getNode() {
     return node;
   }

   public void setNode(Node node) {
     this.node = node;
   }

   public void setColor(RGB color) {
     this.color = color;
   }

}

ChangeColorRequest看起來和一個JavaBean差不多,的確如此,因為Request的作用就是 傳遞翻譯後的鼠標事件。如果你看一下org.eclipse.gef.Request的代碼,你會發現Request 還有一個type屬性,這個屬性一般是一個字符串(在gef的RequestConstants裡預定義了一些 ,如RequestConstants.REQ_SELECTION_HOVER), EditPolicy可以根據它決定是否處理這個 Request。在我們的例子裡,順便定義了這樣一個常量字符串REQ_CHANGE_COLOR,在後面的 ChangeColorEditPolicy裡會用到它。

四、現在有一個問題,這個Request的實例應該在哪裡生成?答案是在Tool裡,用戶在畫 布區域按下鼠標左鍵時,當前 Palette裡被選中的Tool負責創建一個Request。我們現在面對 的這個需求需要我們創建一種新的Tool:ChangeColorTool。我們讓ChangeColorTool繼承 org.eclipse.gef.tools.SelectionTool,因為“上色工具”的用法和“選擇工具”基本上差 不多。顯然,我們需要覆蓋的是handleButtonDown()方法,用來告訴gef如果用戶當前選擇了 這個工具,在畫布區域按下鼠標會發生什麼事情。代碼如下:

import org.eclipse.gef.EditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.tools.SelectionTool;
import org.eclipse.swt.graphics.RGB;
import com.example.model.Node;
import com.example.parts.NodePart;

public class ChangeColorTool extends SelectionTool {
   private RGB color;

   public ChangeColorTool(RGB color) {
     super();
     this.color = color;
   }

   /**
   * If target editpart is an {@link NodePart}, create a {@link ChangeColorRequest} instance,
   * get command from target editpart with this request and execute.
   */
   @Override
   protected boolean handleButtonDown(int button) {
     //Get selected editpart
     EditPart editPart = this.getTargetEditPart();

     if (editPart instanceof NodePart) {
       NodePart nodePart = (NodePart) editPart;
       Node node = (Node) nodePart.getModel();

       //Create an instance of ChangeColorRequest
       ChangeColorRequest request = new ChangeColorRequest(node, color);

       //Get command from the editpart
       Command command = editPart.getCommand(request);

       //Execute the command
       this.getDomain().getCommandStack().execute(command);

       return true;
     }
     return false;
   }

}

五、有了Tool,還需要用ToolEntry把它包裝起來添加到Palette裡。所以我們創建一個名 為 ChangeColorToolEntry並繼承org.eclipse.gef.palette.ToolEntry的類,覆蓋 createTool ()方法,讓它返回我們的ChangeColorTool實例。這個ChangeColorToolEntry代 碼應該很容易理解:

import org.eclipse.gef.SharedCursors;
import org.eclipse.gef.Tool;
import org.eclipse.gef.palette.ToolEntry;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.RGB;

public class ChangeColorToolEntry extends ToolEntry {
   private RGB color;

   public ChangeColorToolEntry(RGB color, String label, String shortDesc, ImageDescriptor iconSmall,
       ImageDescriptor iconLarge) {
     super(label, shortDesc, iconSmall, iconLarge);
     this.color = color;
   }

   @Override
   public Tool createTool() {
     ChangeColorTool tool = new ChangeColorTool(color);
     tool.setUnloadWhenFinished(false);//Switch to selection tool after performed?
     tool.setDefaultCursor(SharedCursors.CROSS);//Any cursor you like
     return tool;
   }

}

六、要把三個這樣的ToolEntry添加到Palette裡,當然是通過修改原來的PaletteFactory 類。為節約篇幅,這裡就不帖它的代碼了,可以下載並參考示例代碼PaletteFactory.java裡 的createCategories()和 createColorDrawer()方法。

到目前為止,ChangeColorRequest已經可以發出了,接下來要解決的問題是如何讓 EditPart處理這個請求。

七、我們知道,gef裡任何對模型的修改都是通過command完成的,因此一個 ChangeColorCommand肯定是需要的。它的execute()方法和undo()方法如下所示:

public class ChangeColorCommand extends Command{

   private RGB oldColor;

   @Override
   public void execute() {
     oldColor = node.getColor();
     node.setColor(color);
   }

   @Override
   public void undo() {
     node.setColor(oldColor);
   }
}

八、EditPolicy負責接收所有的Request,所以還要創建一個 ChangeColorEditPolicy。在下面列出的代碼裡,你會看到我們定義了一個新的“Role”字符 串,過一會兒我們在EditPart上安裝這個EditPolicy的時候要以這個字符串作為Key,以避免 覆蓋EditPart上已有的其他EditPolicy。

import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.AbstractEditPolicy;
import org.eclipse.swt.graphics.RGB;

import com.example.model.Node;

public class ChangeColorEditPolicy extends AbstractEditPolicy {
   final static public String CHANGE_COLOR_ROLE = "CHANGE_COLOR_ROLE";

   @Override
   public Command getCommand(Request request) {
     //Judge whether this request is intersting by its type
     if (request.getType() == ChangeColorRequest.REQ_CHANGE_COLOR) {
       ChangeColorRequest theRequest = (ChangeColorRequest) request;

       //Get information from request
       Node node = theRequest.getNode();
       RGB color = theRequest.getColor();

       //Create corresponding command and return it
       ChangeColorCommand command = new ChangeColorCommand(node, color);
       return command;
     }
     return null;
   }
}

九、最後還是回到EditPart,前面在第二個步驟裡我們曾經修改過的NodePart裡還有最後 一處需要添加,那就是在installEditPolicies()方法裡添加剛剛創建的 ChangeColorEditPolicy:

protected void createEditPolicies() {

   //Add change color editpolicy
   installEditPolicy(ChangeColorEditPolicy.CHANGE_COLOR_ROLE, new ChangeColorEditPolicy());
}

現在我們已經完成了所有必要的修改,來看一下運行結果。

總結一下,需要創建的類有:ChangeColorRequest, ChangeColorTool, ChangeColorToolEntry, ChangeColorCommand, ChangeColorEditPolicy;需要修改的類有: Node, NodePart, PaletteFactory。在實例項目裡,為了方便大家浏覽,所有新創建的類都 放在com.example.request包裡,實際項目裡還是建議分別放在對應的包裡。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved