GEF — 改善使用者體驗,為圖形元素添加建立助手工具條,取代palette的功能

來源:互聯網
上載者:User

這幾天一直在做GEF的一個項目,看過網上的一些資料,覺得能為一些圖形元素添加一個工具條,那將大大提高使用者體驗。網上討論相關問題的好像只有劉剛,但是相比較他的實現,我的想法不同,我的想法是參考每一個Figure的toolTip的實現,通過shell來顯示這個工具條,這樣,我們就不必在palette和圖形工作區之間來回操作了。下面就說說我的想法和實現。這裡需要註明的一點是:我所說的“圖形元素”是指那些非Connection的GEF圖形,比如GEF例子Shape中的RectangleFigure和EllipseFigure,Logic中的LED、AndGate、OrGate等等;或者UML工具中的類圖、活動圖表、狀態機器中的狀態等等;例如:

這個圖中的Work Flow Item就是我所說的圖形元素,而上面的Work Flow Path其實就是兩個圖形元素之間的Connection;

我們都知道Figure是可以設定toolTip的,這個toolTip是顯示在Figure之上的,那麼GEF是怎麼實現的呢?下面先說一下toolTip是如何?的。

toolTip的顯示是由ToolTipHelper類實現的,這個類繼承自PopUpHelper,由這個圖可以看出,PopUpHelper有自己的lws和自己的shell,PopUpHelper完全利用了LightweightSystm和相應的shell來實現彈出式視窗的顯示,顯示是通過show方法實現的,同時這個類裡還有一個Control變數,這個變數表示當前彈出式視窗所屬那個SWT Control。通過這個啟發,我們可以實現任何形式的地彈出式視窗,如果我們願意,我們甚至可以在這個視窗裡顯示表格、按鈕甚至樹型結構等等;而toolTip僅僅是一個簡簡單單的實現而已。

那麼需要實現浮動工具條的時候,我們需要做以下幾個方面的工作:

1、當滑鼠在某一個圖形元素上Hover時,應該顯示這個工具條;

 

2、工具條的顯示應該受幾個方面的限制:
     如果滑鼠移動到工具條上,工具條應該始終顯示;
     如果滑鼠沒有進入到工具條上,那麼不論滑鼠是Hover還是Move,工具條都應該顯示一定的時間,然後消失;

3、如果在工具條上選中了某一個工具,那麼應該構造相應的Command,這個Command可以是普通的Command用來構造圖形元素,也可以是ConnectionCommand用來在兩個圖形元素之間構造Connection;只是這兩個Command是有區別的,前者可以直接執行,而後者由於需要一個目標的圖形元素,因此命令的執行需要兩個階段,首先要構造一個Start Command,然後當選定了某個靶心圖表形元素後“Complete Command”,其實這就是EditPolicy.GRAPHICAL_NODE_ROLE這個角色名稱定義的預設操作。

4、zoom實現對座標位置的影響;

好了,下面就給出解決方案。

 

1、對於以上討論中的第一點,我們必須實現圖形元素對應Figure的MouseMotionListener,並在MouseHover方法中實現:
     LightweightSystm的構造;
     Shell的構造;
     浮動工具條對應Figure的構造;
     在合適的位置顯示shell;-- shell.setVisible(true);
     建立Timer,由這個定時器控制浮動工具條的顯示與否;
以上工作的前4步是標準的Draw2D程式,只要懂Draw2D,應該沒有問題。但是這裡需要注意以下幾點:
·Shell在構造的過程中,往往需要一個parent,這個parent是如何獲得的呢?---- 我們可以在相應的EditPart中調用getViewer().getControl()得到Control後然後調用其getShell ()方法得到parent;其實我們動態跟蹤ToolTipHelper的執行會發現,這就是它的實現方法;
·shell顯示位置的確定,必須是螢幕上的絕對位置,為了這件事,我鼓搗了半天。尤其是多螢幕的時候,如果處理的不對,這種錯誤更加明顯,明明程式運行在分屏的一個螢幕上,可是shell卻顯示在另外一個螢幕上,實在讓人哭笑不得。這裡最簡單的一個處理方法就是將PopUpHelper和ToolTipHelper的實現拷貝過來就可以了;
·Timer需要定義為輪詢形勢,也就是每隔一定時間執行一次;如下。其中3000代表3秒鐘。第一個3000表示3秒後第一個執行,第二個3000表示其後每隔3秒執行一次;

timer = new Timer(true);
  timer.schedule(new TimerTask() {
   public void run() {
    Display.getDefault().syncExec(new Thread() {
     public void run() {
      hide();
      timer.cancel();
      floattingFigure = null;
     }
    });
   }
  }, 3000, 3000);

 

//這個方法通過判斷滑鼠是否進入工具條來決定是否繼續顯示它,注意entered變數;

protected void hide() {
  if (shell != null && !shell.isDisposed() && !entered)
   shell.setVisible(false);
 }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

以上就是我們關心的圖形元素需要做的所有工作;如所示,滑鼠在時看不見;

2、對於工具條來說,它需要實現MouseListener和MouseMotionListener,前者完成在點選某個工具項時Command的構造,而後者完成滑鼠是否進入工具條的判斷;由此可知我們需要一個boolean變數entered來表示滑鼠是否進入了工具條,進入則為true、離開就為false;這樣呼應上面的實現,每次定時器執行時,都會判斷entered是否為true,如果“是”則繼續顯示,否則將會隱藏shell;

3、對於MouseMotionListener的實現,我們可以考慮兩種情況,也就是上面所說的兩種類型的Command,如果是第一種Command,我們可以在浮動工具條的mousePressed方法中直接構造這個方法,然後調用命令棧去執行他:getViewer().getEditDomain().getCommandStack().execute(command);那麼相應的命令立刻執行,並可以Undo;如果我們用過Eclipse3.5 Galileo Modller的話,會發現,他的UML2外掛程式的實現就是這樣的;當滑鼠在工作區上停留時,會顯示一個工具條,根據當前構造的UML圖的不同,工具條上的可選工具也是不一樣的,一旦某個工具被選中並且點擊,相應的圖形元素就被建立了;但是對於第二種情況,也就是ConnectionCommad,處理可就不是那麼簡單了,我們需要在mousePressed方法中建立“start command”,然後在mouse Released方法中將這個Command補全,也就是完成Complete Command,然後再執行;

·這裡需要注意的是,由於這是工具條的滑鼠事件,所以“事件”Event中的滑鼠位置是相對於工具條座標原點的,裡面需要一個轉化過程。
·其二,如果你的GEF程式中支援Zoom,那麼當滑鼠釋放時,真正滑鼠移動的距離(相對於工具條原點的位移量)應該是滑鼠位置與zoom率的比值,記住是比值,不是乘積。

劉剛對於建立助手的實現,如果是第一種情況,他將工具條放在了Handle層裡,如果是第二種實現(串連),他是將editdomain的activeTool設定為connection的tool,然後指定targetEditPart,我還沒有嘗試過,不知道該如何?;但是不管怎麼說,兩種方法都能實現。我們可以根據喜好選擇不同的方法;

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.