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


程式碼如下
  1. public class ZestGraphTest extends ViewPart{
  2. org.eclipse.swt.widgets.List groupSets;
  3. private int selectedIndex = -1;
  4. @Override
  5. public void createPartControl(Composite parent) {
  6. // TODO Auto-generated method stub
  7. String[] nodeName = {"main", "children1", "children2", "children3"};
  8. //1. split Layout to two columns
  9. Composite composite = new Composite(parent, SWT.NONE);
  10. GridLayout gl = new GridLayout(2, false);
  11. gl.marginHeight = 0;
  12. gl.marginWidth = 0;
  13. composite.setLayout(gl);
  14. //2. create SWT List and set layout
  15. groupSets = new org.eclipse.swt.widgets.List(composite, SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL);
  16. GridData grid = new GridData(SWT.LEFT, SWT.FILL, false, true, 1, 1);
  17. grid.widthHint = 200;
  18. groupSets.setLayoutData(grid);
  19. //3. create List, Graph, GraphNode, GraphConnection
  20. GraphNode nodesList[] = new GraphNode[nodeName.length];
  21. final Graph graph = new Graph(composite, SWT.BORDER);
  22. GraphNode mainNode = null;
  23. for(int i = 0 ; i < nodeName.length ; i++){
  24. groupSets.add(nodeName[i]);
  25. nodesList[i] = new GraphNode(graph, SWT.NONE, nodeName[i]);
  26. if(i == 0){
  27. mainNode = nodesList[i];
  28. mainNode.setTooltip(new Label("Hello World!!\r\nHello World!!"));
  29. }else{
  30. new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, mainNode, nodesList[i]);
  31. }
  32. }
  33. graph.setLayoutAlgorithm(new RadialLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
  34. GridData theGriddata = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
  35. graph.setLayoutData(theGriddata);
  36. //4. define graph selection event
  37. graph.addSelectionListener(new SelectionAdapter(){
  38. public void widgetSelected(SelectionEvent e) {
  39. if(selectedIndex > -1){
  40. Graph g = (Graph) e.getSource();
  41. GraphItem sitem = (GraphItem) e.item;
  42. GraphItem item[] = {sitem};
  43. g.setSelection(item);
  44. }
  45. }
  46. });
  47. //5. define List selection event
  48. groupSets.addSelectionListener(new SelectionListener(){
  49. public void widgetSelected(SelectionEvent e) {
  50. selectedIndex = groupSets.getSelectionIndex();
  51. Event event = new Event();
  52. @SuppressWarnings("unchecked")
  53. List nodeLists = graph.getNodes();
  54. GraphNode node = nodeLists.get(selectedIndex);
  55. //node selected by trigger
  56. event.widget = graph;
  57. event.item = node;
  58. graph.notifyListeners(SWT.Selection, event);
  59. //node MouseHover initialize by trigger
  60. event.x = 0;
  61. event.y = 0;
  62. graph.notifyListeners(SWT.MouseHover, event);
  63. //node MouseHover to show tooltip by trigger
  64. event.x = node.getLocation().x;
  65. event.y = node.getLocation().y;
  66. graph.notifyListeners(SWT.MouseHover, event);
  67. selectedIndex = -1;
  68. }
  69. @Override
  70. public void widgetDefaultSelected(SelectionEvent e) {
  71. // TODO Auto-generated method stub
  72. }
  73. });
  74. }
  75. @Override
  76. public void setFocus() {
  77. // TODO Auto-generated method stub
  78. }
  79. }
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是否

要顯示!

三. 結果展示


留言