Eclispe Plug-in - Eclipse Zest GraphNode show tooltip by MouseHover trigger

如果你今天要在Eclipse plugin內顯示Graph node與node之間的視覺化圖形關聯的話,可以套

用Eclipse Zest Library來進行繪圖!

在這邊不是要說明怎麼使用Zest來建立節點間的關聯,而是要說明假設在不移入節點的情況

,如何透過其他元件來觸發移入或點擊節點效果進而開啟提示訊息!

使用版本

Eclipse Zest version : 3.10.1 for Mars.1

Eclipse version : Mars.2

一、安裝Eclipse Zest

請至網站下載GEF3-Update-3.10.1.zip

Eclipse → Help → Install New Software

將剛剛的zip檔載入進行安裝的動作

二、範例說明

首先,範例程式UI呈現在Eclipse view上,會分割畫面成左右兩部分。

左半邊為SWT List;右半邊為Zest Graph


程式碼如下
public class ZestGraphTest extends ViewPart{
 org.eclipse.swt.widgets.List groupSets;
 private int selectedIndex = -1;

 @Override
 public void createPartControl(Composite parent) {
  // TODO Auto-generated method stub
  String[] nodeName = {"main", "children1", "children2", "children3"};
  
  //1. split Layout to two columns
  Composite composite = new Composite(parent, SWT.NONE);
  GridLayout gl = new GridLayout(2, false);
  gl.marginHeight = 0;
  gl.marginWidth = 0;
  composite.setLayout(gl);
  
  //2. create SWT List and set layout
  groupSets = new org.eclipse.swt.widgets.List(composite, SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL);
  GridData grid = new GridData(SWT.LEFT, SWT.FILL, false, true, 1, 1);
  grid.widthHint = 200;
  groupSets.setLayoutData(grid);
  
  //3. create List, Graph, GraphNode, GraphConnection 
  GraphNode nodesList[] = new GraphNode[nodeName.length];
  final Graph graph = new Graph(composite, SWT.BORDER);
  GraphNode mainNode = null;
  for(int i = 0 ; i < nodeName.length ; i++){
   groupSets.add(nodeName[i]);
   nodesList[i] = new GraphNode(graph, SWT.NONE, nodeName[i]);
   if(i == 0){
    mainNode = nodesList[i];
    mainNode.setTooltip(new Label("Hello World!!\r\nHello World!!"));
   }else{
    new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, mainNode, nodesList[i]);
   }
  }
  graph.setLayoutAlgorithm(new RadialLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
  GridData theGriddata = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
  graph.setLayoutData(theGriddata);
  
  //4. define graph selection event
  graph.addSelectionListener(new SelectionAdapter(){
   public void widgetSelected(SelectionEvent e) {
    if(selectedIndex > -1){
     Graph g = (Graph) e.getSource();
     GraphItem sitem = (GraphItem) e.item;
     GraphItem item[] = {sitem};
     g.setSelection(item);
    }
   }
  });
  
  //5. define List selection event
  groupSets.addSelectionListener(new SelectionListener(){
   public void widgetSelected(SelectionEvent e) {
    selectedIndex = groupSets.getSelectionIndex();
    
    Event event = new Event();
    @SuppressWarnings("unchecked")
    List nodeLists = graph.getNodes();
    GraphNode node = nodeLists.get(selectedIndex);
    
    //node selected by trigger
    event.widget = graph;
    event.item = node;
    graph.notifyListeners(SWT.Selection, event);
    
    //node MouseHover initialize by trigger
    event.x = 0;
    event.y = 0;
    graph.notifyListeners(SWT.MouseHover, event);
    
    //node MouseHover to show tooltip by trigger
    event.x = node.getLocation().x;
    event.y = node.getLocation().y;
    graph.notifyListeners(SWT.MouseHover, event);
    
    selectedIndex = -1;
   }

   @Override
   public void widgetDefaultSelected(SelectionEvent e) {
    // TODO Auto-generated method stub
    
   }
  });
 }

 @Override
 public void setFocus() {
  // TODO Auto-generated method stub
  
 }
}

2.1、繼承ViewPart

請在plugin.xml內建立view extension


2.2、初始化元件

請見註解1 ~ 3部分

分別為分割視窗及建立List、Graph、GraphNode還有GraphConnection

特別注意的地方是

mainNode.setTooltip(new Label("......"));

這一段code針對該節點為另外指定Tooltip,若沒有另外指定的話預設是帶入節點名稱

2.3、定義事件處理

先說明List的事件定義

當我們點擊左半邊的List其中一個項目時

此時會先做node selection event的trigger,需在item內指定node,可透過graph.getNodes取得其

物件,目的是Graph是由其本身綁定事件,無法透過GraphNode來綁定,因此當指定item的

node時,回到graph selection事件處理可以由graph object setSelection來達到node被點擊的效

果! 這就如同您直接點擊node的行為是一樣的!

再過來是執行node MouseHover初始化的trigger

這邊會覺得奇怪,怎麼還需要做初始化的動作,直接做下一個MouseHover不就好了?!

原因在於



追到底層的code,查了一下發現要顯示tooltip時會呼叫displayToolTipNear,這邊會判斷

當下如果currentTipSource == hoverSource時則不進入條件,因此當您第一次點擊List的

main時可以正常進入,因為currentTipSource = null,但是當您連續第二次觸發main時,

此時currentTipSource 會等於 hoverSource,因此會無法正常trigger顯示tooltip!

當然,如果您是換點擊其他item,此時當然就會不等於,但是我們須預防會連續點擊!

因此,才想說使其currentTipSource被初始化,可以確認不等於hoverSource

PS. 也許這並不一定是唯一做法,僅供參考!!

那為啥正常去節點上直接hover後,再一次hover也可以正常顯示?

因為會有hover離開節點的事件處理,在這時就會初始化currentTipSource了!

也許這是處理MouseHover trigger不用作初始化的另一個解決方式吧?!

緊接著,為啥要設定event.x及event.y呢?

這邊也是追底層的code,發現graph內的tooltip到底哪一個要顯示。首先由root往下追蹤,再

來會掃到各節點及其擁有的Figure,由method去判斷findFigureAt(x, y)及containsPoint(x, y)是

否成立! 也就是判斷這個點是否涵蓋至Figure內! 如此一來就可以知道哪一個node的tooltip是否

要顯示!

三. 結果展示


留言