nighty

          折騰的年華
          posts - 37, comments - 143, trackbacks - 0, articles - 0

          RssOwl2源碼閱讀 -- ActionSet

          Posted on 2008-08-21 11:29 寒武紀 閱讀(1803) 評論(0)  編輯  收藏 所屬分類: Eclipse
              ActionSet是Eclipse RCP里面一非常重要的概念,因為菜單、工具欄、上下文菜單、狀態欄很多操作都是共享的,所以Action就是用來處理重復出現的東西。至于Eclipse里面定義ActionSet有非常多的技巧,可能無法一一列舉,而且使用方法也多種多樣。下面介紹的是RssOwl2項目的ui源代碼部分的一小塊。
             1.  菜單的插入點 -- GroupMarker和Separator的使用
                  ApplicationActionBarAdvisor類是定義全局所有Action插入點和入口,查看fillMenuBar(IMenuManager)方法,為了簡化,以其中的輔助方法createFileMenu(IMenuManager)為例,講述一下實現菜單“文件”的內容,先看一下菜單的結構

                 像Close,Import...之類的非常簡單,看一下它是如何實現New這個子菜單的。首先看一下它的源代碼如何定義插入點
               
          /* Menu: File */
            
          private void createFileMenu(IMenuManager menuBar) {
              MenuManager fileMenu 
          = new MenuManager("&File", IWorkbenchActionConstants.M_FILE);
              menuBar.add(fileMenu);

              fileMenu.add(
          new GroupMarker(IWorkbenchActionConstants.FILE_START));
              fileMenu.add(
          new GroupMarker(IWorkbenchActionConstants.NEW_EXT));
              fileMenu.add(
          new Separator());

              fileMenu.add(getAction(ActionFactory.CLOSE.getId()));
              fileMenu.add(getAction(ActionFactory.CLOSE_ALL.getId()));
              fileMenu.add(
          new GroupMarker(IWorkbenchActionConstants.CLOSE_EXT));
              fileMenu.add(
          new Separator());
              fileMenu.add(getAction(ActionFactory.SAVE_AS.getId()));
              fileMenu.add(
          new GroupMarker(IWorkbenchActionConstants.SAVE_EXT));
              fileMenu.add(
          new Separator());
              fileMenu.add(getAction(ActionFactory.PRINT.getId()));

              fileMenu.add(
          new Separator());
              fileMenu.add(
          new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));

              fileMenu.add(fReopenEditors); 
          // TODO Consider moving into a "Go" Menu!

              fileMenu.add(
          new Separator());
              fileMenu.add(
          new GroupMarker(IWorkbenchActionConstants.FILE_END));
              fileMenu.add(
          new Separator());

              fileMenu.add(getAction(ActionFactory.QUIT.getId()));
            }
                 其中有一行fileMenu.add(new GroupMarker(IWorkbenchActionConstants.NEW_EXT)); 這里是定義一個GroupMarker作為組標記,把子菜單New容納進來。這個NEW_EXT的值是:new.ext
                現在跳回到plugin.xml去看一下它的ActionSet定義,結構如下:
          ,點擊New(menu),它的path值為:file/new.ext,這個路徑就是在createFileMenu方法定義的路徑,第一個是“File”本身的ID。也就是把子菜單New(menu)插入到指定的那個GroupMarker,ID為new.ext。然后定義了三個ID分別為bookmark,newsbin,searchmark,的groupmarker和一個folder的separator,這個三ID分別就對應上面actionSet定義的三個action,以其中的Bookmark(action)為例,它的menubarPath為:file/new_sub/bookmark,代表插入到"File"主菜單中定義的new_sub子菜單中,new_sub是New(menu)的ID。因為folder是定義為separator,所以它會有一條分隔線。這只是RssOwl的定義方法,其實以前自己做開發的時候是沒有這樣定義的,而且把子菜單New也寫在方法fillMenuBar中的,菜單把ID都寫在里面,ActionSet的配置就沒有子菜單出現了,但是這樣定義看起來就比較亂。采用這種寫法感覺比較簡潔。
              2.  Action的實現
                 仍以bookmark為例,它的實現類是NewBookMarkAction,實現了IWorkbenchWindowActionDelegate, IObjectActionDelegate二個接口,第一個是ActionSet指定實現接口,第二個是對象操作菜單要求實現的接口(但事實發現沒有再定義它的配置,可能是internal版本的原因),也就是說這個Action是多功能,它將會出現在主菜單,工具欄,和局部的右鍵菜單上。主菜單和工具欄的位置都在ActionSet配置定義了,看看它的右鍵菜單實現是在哪里的,這個右鍵是在視圖Bookmarks定義的,那么跳轉到org.rssowl.ui.internal.views.explorer.BookMarkExplorer類去看看。里面有一個hookContextualMenu()方法,就是定義它的右鍵菜單的,看一下代碼實現:
          private void hookContextualMenu() {
              MenuManager manager 
          = new MenuManager();

              
          /* New Menu */
              MenuManager newMenu 
          = new MenuManager("New");
              manager.add(newMenu);

              
          /* New BookMark */
              newMenu.add(
          new Action("Bookmark"{
                @Override
                
          public void run() {
                  IStructuredSelection selection 
          = (IStructuredSelection) fViewer.getSelection();
                  IFolder parent 
          = getParent(selection);
                  IMark position 
          = (IMark) ((selection.getFirstElement() instanceof IMark) ? selection.getFirstElement() : null);
                  
          new NewBookMarkAction(fViewSite.getShell(), parent, position).run(null);
                }


                @Override
                
          public ImageDescriptor getImageDescriptor() {
                  
          return OwlUI.BOOKMARK;
                }

              }
          );

             
          //其它定義
          }
               原來實現也很簡單,只是往MenuManager里面添加一個Action而已,而且run方法就是直接調用定義好的NewBookMarkAction的run方法,但是把選中對象做為參數傳進去,因為這個new是涉及當前上下文選擇對象的。
              3. 下拉類型的工具按鈕定義
              非常常見的Dropdown類型的工具欄按鈕可以把功能類型的按鈕歸為一類,做成一個下拉菜單形式,有默認的按下功能,也有可以選擇其它類似功能的下三角形式,樣子如下:

              這個dropdown的Action是定義在ActionSet配置里的。style是pulldown類型的,所以實現類NewTypeDropdownAction實現了IWorkbenchWindowPulldownDelegate接口,它的run方法就是定義默認點擊不做選擇時的事情,這個下拉菜單是實現getMenu(Control parent)方法而來,它定義了如何生成這個菜單,這就用到了最原始的SWT中的MenuItem了,并且為它們添加SelectionListener,方法實現,不用說都知道了,又是New一個先前定義好的NewBookMarkAction類,然后又是調用它的run方法。所以總結一下,Action的重用不一定是這個類的重用,關鍵是它的run方法的重用,在不同的場景下它的外在表現形式可能會多種多樣,但是它的run內容是一致的。像添加這種添加的run大部分時候都是彈出一個對話框,而對話框大都又是Winzard類型的,因為Winzard可以共享放到dialog里面。所以這種復用的思想在Eclipse里面隨處可見。
             歸結一下,其實這些技巧都是次要的,因為做GUI一個比較痛苦的事情就是經常要寫很多重復類似的代碼,抽取的不好,可能就變得不倫不類了。怎么利用它的這種思想,把復用的代碼都抽取在一起,而閱讀起來又比較輕松才是關鍵。
             知道的就這些,先介紹到這里,下次再談談其它新的發現。


          剛進場的時候戲就落幕
          主站蜘蛛池模板: 淮滨县| 沽源县| 武清区| 东兰县| 工布江达县| 新野县| 山东省| 湖口县| 广德县| 龙江县| 昌图县| 云林县| 钦州市| 鱼台县| 公主岭市| 新乐市| 沂源县| 且末县| 长宁区| 叙永县| 东乡| 霍山县| 马尔康县| 浑源县| 赣榆县| 海丰县| 绥江县| 西青区| 彭水| 原平市| 买车| 张家川| 静乐县| 丰宁| 紫云| 江安县| 广丰县| 阿拉善盟| 五家渠市| 达日县| 郓城县|