// 下階層用テンプレート
#topicpath
----
//ここにコンテンツを記述します。
#contents

*Eclipse/RCPのメニューバーの構築 [#xfe6d579]

Eclipse/RCPのメニューバーの構築は、以下の2つの方法で行うことができます。
-プログラムからプログラマティカルに
-拡張ポイントから宣言的に

[[TUTORIALS 26 Developing for the Rich Client Platform:http://www.eclipsecon.org/2005/tutorials.php]]
によると
-(メニューと、常に表示しておくアクションなど)最小のスケルトンをプログラマティカルに
-それ以外は宣言的に

となっていますね。



**プログラムからプログラマティカルに [#f392fc18]
さて、スケルトンとなる最小の構成をEclipse/RCPのフレームワークで作ります。

RCPは
 IPlatformRunnable -> WorkbenchAdvisor 
 -> WorkbenchWindowAdvisor -> ActionBarAdvisor 
(の実装クラス)という順番に呼び出されるパタンになっていて、メニューバーはこの
 org.eclipse.ui.application.ActionBarAdvisor
内の
 protected void makeActions(IWorkbenchWindow window);
 protected void fillMenuBar(IMenuManager menuBar) ;
をOverrideすることで実装します。

ここでは下記のように実装しました。



-ActionBarAdvisor の実装クラス

 package nu.mine.kino.plugin.samples.rcp;
 
 import org.eclipse.jface.action.IMenuManager;
 import org.eclipse.jface.action.MenuManager;
 import org.eclipse.jface.action.Separator;
 import org.eclipse.ui.IWorkbenchActionConstants;
 import org.eclipse.ui.IWorkbenchWindow;
 import org.eclipse.ui.actions.ActionFactory;
 import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
 import org.eclipse.ui.application.ActionBarAdvisor;
 import org.eclipse.ui.application.IActionBarConfigurer;
 
 public class ApplicationActionBarAdvisor extends ActionBarAdvisor {
 
   private IWorkbenchWindow window;
   private IWorkbenchAction quitAction;
   private IWorkbenchAction aboutAction;
   private IWorkbenchAction helpSearchAction;
 
   public ApplicationActionBarAdvisor(IActionBarConfigurer configurer) {
     super(configurer);
     window = configurer.getWindowConfigurer().getWindow();
   }
 
   protected void makeActions(IWorkbenchWindow window) {
     quitAction = ActionFactory.QUIT.create(window);
     register(quitAction);
     aboutAction = ActionFactory.ABOUT.create(window);
     register(aboutAction);
     helpSearchAction = ActionFactory.HELP_SEARCH.create(window);
     register(helpSearchAction);
   }
 
   protected void fillMenuBar(IMenuManager menuBar) {
     menuBar.add(createFileMenu());
     menuBar.add(createHelpMenu());
   }
 
   /**
    * Creates and returns the File menu.
    */
   private MenuManager createFileMenu() {
     MenuManager menu = new MenuManager("&File",
         IWorkbenchActionConstants.M_FILE);
     menu.add(quitAction);
     return menu;
   }
 
   private MenuManager createHelpMenu() {
     // 根っこのメニュー追加。
     MenuManager menu = new MenuManager("&Help",
         IWorkbenchActionConstants.M_HELP); // helpというキー値
     menu.add(helpSearchAction);
     menu.add(new Separator("group01"));
     // ヘルプと、aboutの間にgroup01というグループを追加
     menu.add(aboutAction);
     return menu;
   }
 }

これで、以下のようにメニューバーが構築されました。


#ref(menu01.png)

 [ワークベンチ]
    |
    |-[File]
    |   -[終了]
    |
    |-[Help]
    |   -[検索]
    |   -[○○について]

ポイントは
-すでに定義済みのアクションは
 quitAction = ActionFactory.QUIT.create(window); <- 終了
などActionFactoryから取得できる

-protected void fillMenuBar(IMenuManager menuBar);

がワークベンチのメニューバーのインスタンスなので、そこにアクションをaddしていく

などです。

***グループ名などについて [#u9f12328]
さて、先のコードで、
 MenuManager menu = new MenuManager("&Help",IWorkbenchActionConstants.M_HELP);
や
 menu.add(new Separator("group01"));
などがありました。この IWorkbenchActionConstants.M_HELP (文字列は"help")や、group01などは、拡張ポイントを使った宣言的メニュー追加で必要になってきます。拡張ポイントから宣言的にメニューにアクションを追加する際に、どこに追加するのかをこの名称で指定します。具体的に説明すると、まず先のコーディングで、各メニューの要素には以下の名前が付けられたことになります。

 [ワークベンチ]
    |
    |-[File]            - "file"  <- IWorkbenchActionConstants.M_FILE
    |   -[終了]
    |
    |-[Help]            - "help"  <- IWorkbenchActionConstants.M_HELP
    |   -[検索]
    |   -"セパレータ"   - "group01"
    |   -[○○について] - 

この場合、"セパレータ"部分は、正式名称((完全修飾メニュー・パスというらしい))は
 help/group01 (メニュー名/グループ名)
となります。この名称を、拡張ポイントでアクションを追加するときに使用するわけです。



**拡張ポイントから宣言的に [#ge84d99c]
では先の"セパレータ"部分にアクションを追加します。セパレータの完全修飾メニュー・パスは
 help/group01
でした。


plugin.xmlに以下を追加します。

 <extension point="org.eclipse.ui.actionSets" >
   <actionSet label="ラベル(つかってる?)"
     visible="true" id="nu.mine.kino.plugin.samples.rcp.actionsets">
     <action
       label="追加アクション。" <- 表示されるアクション名
        class="nu.mine.kino.plugin.samples.rcp.actions.HogeAction" <- 実装クラス
        menubarPath="help/group01" <- さっきの完全修飾メニュー・パス
        id="nu.mine.kino.plugin.samples.rcp.actions.hogeaction">
     </action>
   </actionSet>
 </extension>
これで先のhelp/group01の箇所に "追加アクション。" というアクションが追加されました。

#ref(menu02.png)


図で書くと以下の通りですね。
 [ワークベンチ]
    |
    |-[File]                   - "file"     <- IWorkbenchActionConstants.M_FILE
    |   -[終了]
    |
    |-[Help]                   - "help"     <- IWorkbenchActionConstants.M_HELP
    |   -[検索]
    |   -"セパレータ"          - "group01"
    |   -[追加アクション。]    -            <- plugin.xmlで追加
    |   -[○○について] - 





このように、セパレータなどを用いて、提供側の開発者がメニューを追加できるように「開いておいてくれた」場合、他のプラグイン開発者は、完全修飾メニュー・パスを知ることで容易にアクションを追加することができるわけですね。



*** アクションではなく、サブメニューを追加する [#hed5215b]
次に、サブメニューを追加したいと思います。具体的には次のようにしたいと思います。

 [ワークベンチ]
    |
    |-[File]                   - "file"     <- IWorkbenchActionConstants.M_FILE
    |   -[終了]
    |
    |-[Help]                   - "help"     <- IWorkbenchActionConstants.M_HELP
    |   -[検索]
    |   -"セパレータ"          - "group01"
    |   -[追加メニュー。]      - "menu01"   <- plugin.xmlで追加
    |      -"セパレータ"       - "sepa01"   <- plugin.xmlで追加
    |      -[追加アクション。] -            <- plugin.xmlで追加
    |   -[○○について] - 

セパレータ部分に「追加メニュー。」というサブメニューを追加し、その下にさっきのアクションを追加したいと思います。

plugin.xmlに以下の通り記述します。さっきのactionSetsはいったん削除しましょう。
 <extension point="org.eclipse.ui.actionSets" >
   <actionSet label="ラベル(つかってる?)"
     visible="true" id="nu.mine.kino.plugin.samples.rcp.actionsets">
       <menu
          id="menu01"       <- 名称は menu01
          label="追加メニュー。"
          path="help/group01">  <-このサブメニューはセパレータの場所に追加する
         <separator name="sepa01"/> <-さらにセパレータを下に追加
       </menu>
     <action
       label="追加アクション。"
       class="nu.mine.kino.plugin.samples.rcp.actions.HogeAction"
       menubarPath="help/menu01/sepa01"
       id="nu.mine.kino.plugin.samples.rcp.actions.hogeaction">
     </action>
   </actionSet>
 </extension>

順に見ていきます。
 <menu
   id="menu01"
   label="追加メニュー。"
   path="help/group01">
   <separator name="sepa01"/>
 </menu>
で「pathの箇所にlabelのサブメニューをidの名称で追加します」という意味になります。でその箇所の完全修飾メニュー・パスは help/menu01 となります。[メニュー名/グループ名]なのでhelp/menu01となるんですね。

次にセパレータを追加しています。セパレータの完全修飾メニュー・パスは
 help/menu01/sepa01
となります。

あとはアクションですが、先と同じで
 menubarPath="help/menu01/sepa01"
によって、先のサブメニューの下のセパレータ部分にこのアクションが挿入されることになります。





*** 複数のアクションを追加する [#i51aa936]
続いて以下のように複数のアクションを追加しました。
   <actionSet label="ラベル(つかってる?)"
     visible="true" id="nu.mine.kino.plugin.samples.rcp.actionsets">
     <menu
      id="menu01"
      label="追加メニュー。"
      path="help/group01">
      <separator name="sepa01"/>
     </menu>
     <action
       label="追加アクション。"
       class="nu.mine.kino.plugin.samples.rcp.actions.HogeAction"
       menubarPath="help/menu01/sepa01"
       id="nu.mine.kino.plugin.samples.rcp.actions.hogeaction">
     </action>
     <action
       label="追加アクション2。"
       class="nu.mine.kino.plugin.samples.rcp.actions.HogeAction"
       menubarPath="help/group01" 
       id="nu.mine.kino.plugin.samples.rcp.actions.hogeaction2">
     </action>
    </actionSet>



予想通り

 [ワークベンチ]
    |
    |-[File]                   - "file"     <- IWorkbenchActionConstants.M_FILE
    |   -[終了]
    |
    |-[Help]                   - "help"     <- IWorkbenchActionConstants.M_HELP
    |   -[検索]
    |   -"セパレータ"          - "group01"
    |   -[追加アクション2。]"  - "group01"  <- plugin.xmlで追加
    |   -[追加メニュー。]      - "menu01"   <- plugin.xmlで追加
    |      -"セパレータ"       - "sepa01"   <- plugin.xmlで追加
    |      -[追加アクション。] - "sepa01"   <- plugin.xmlで追加
    |   -[○○について] - 


となりました。



*** 存在しない完全修飾メニュー・パスを指定する [#v4898d72]
さらに以下の内容をplugin.xmlに追加します。
 <action
   id="nu.mine.kino.plugin.samples.rcp.action3"
   label="追加アクション3"
   menubarPath="help/hogehoge" <- 存在しない完全修飾メニュー・パス
 />

すると
#ref(menu03.png)

一番下に追加されました。

***まとめると、以下のようになります。 [#caa1b6d6]
-プログラムで完全修飾メニュー・パスを追加して、メニューを「開いて」おく
-完全修飾メニュー・パスを指定して、アクションを追加できる
-完全修飾メニュー・パスを指定して、サブメニューを追加できる(そのとき下にセパレータを追加しよう)
-サブメニュー追加時は、新しい名称をid要素で定義する(help/menu01など)
-サブメニューの下に追加したセパレータの箇所へのアクションの追加はhelp/menu01/sepa01の様に、サブメニューの完全修飾メニュー・パス/セパレータ名となる
-サブメニューは子要素がないと表示されない
-完全修飾メニュー・パスの箇所には、複数のメニューやアクションを追加できる
-存在しない完全修飾メニュー・パスを指定すると、一番下に追加される





***サブメニューの下にさらにサブメニューを表示する。 [#u28a7585]
最後に、以下のような階層的なメニュー構造を作ってみたいと思います。
次に、以下のような階層的なメニュー構造を作ってみたいと思います。

 [ワークベンチ]
    |
    |-[File]                                - "file"     <- IWorkbenchActionConstants.M_FILE
    |   -[終了]
    |
    |-[Help]                                - "help"     <- IWorkbenchActionConstants.M_HELP
    |   -[検索]
    |   -"セパレータ"                       - "group01"
    |   -[追加メニュー。]                   - "menu01"   <- plugin.xmlで追加
    |      -"セパレータ"                    - "sepa01"   <- plugin.xmlで追加
    |      -[追加アクション。]              -            <- plugin.xmlで追加
    |      -[さらに下にメニュー。]          - "menu02"   <- plugin.xmlで追加
    |        -"セパレータ"                  - "sepa02"   <- plugin.xmlで追加
    |        -[さらに下に追加アクション。]  -            <- plugin.xmlで追加
    |   -[○○について] - 


#ref(menu04.png)



plugin.xmlは以下のようにします。
 <actionSet label="ラベル(つかってる?)"
   visible="true" id="nu.mine.kino.plugin.samples.rcp.actionsets">
   <menu
     id="menu01"
     label="追加メニュー。"
     path="help/group01">
     <separator name="sepa01"/>  <- 完全名は help/menu01/sepa01
   </menu>
   <action
     label="追加アクション。"
     class="nu.mine.kino.plugin.samples.rcp.actions.HogeAction"
     menubarPath="help/menu01/sepa01"
     id="nu.mine.kino.plugin.samples.rcp.actions.hogeaction">
   </action>
   <menu
     id="menu02"
     label="さらに下にメニュー。"
     path="help/menu01/sepa01">   <- help/menu01/sepa01 の場所にサブメニュー追加
     <separator name="sepa02"/>   <- 完全名は help/menu01/menu02/sepa02
   </menu>
   <action
     id="nu.mine.kino.plugin.samples.rcp.action5"
     label="さらに下に追加アクション。"
     menubarPath="help/menu01/menu02/sepa02" >
   </action>
  </actionSet>


ポイントはhelp/menu01/sepa01に追加したサブメニューの完全修飾メニュー・パスは、
 help/menu02/ ではなく help/menu01/menu02/
となることです。即ちそのしたのセパレータも
 help/menu01/menu02/sepa02
となります。従ってそのセパレータに追加するアクションのmenubarPathの指定は
   <action
     id="nu.mine.kino.plugin.samples.rcp.action5"
     label="さらに下に追加アクション。"
     menubarPath="help/menu01/menu02/sepa02" >  <- これ
   </action>
となるわけです。



*** トップレベルのメニューにアクションを追加したい。 [#k713bb2e]
トップレベルのメニュー(ワークベンチが保持するIMenuManagerのメニュー)へメニューを追加する方法です。プログラマティカルにやる方法はまだわかんない(コメントに裏技を載せた)けど、宣言的にやるのは、以下の通り:

 <extension
     point="org.eclipse.ui.actionSets">
  <actionSet
      id="rcpmail.actionSet8"
      label="rcpmail.actionSet8"
      visible="true">  <-これ、重要!!
     <menu
       id="topmenu"
       label="トップメニュー">
      <separator name="sepa01"/>
     </menu>
     <action
       id="rcpmail.action10"
       label="アクション2"
       menubarPath="topmenu/sepa01"
       style="push"/>
     <action
       id="rcpmail.action9"
       label="アクション1"
       menubarPath="topmenu/sepa01"
       style="push"/>
  </actionSet>
 </extension>

参考:~
[[3−3.メニューバー、ツールバーとアクションの紐付け(アクションの登録):http://www.willbe-computing.jp/modules/eclipsercp3/index.php?id=8]]



----
この記事は
#vote(おもしろかった[1],そうでもない[0])
-menu要素(サブメニュー)の場合は、その場所を指定して、そのしたにメニューを追加するので、新しい名前を付ける必要がある。それがid属性なんですね。何となく、わかってきた。。 -- [[きの]] &new{2006-03-02 20:38:36 (木)};
-メニュー自体のインスタンス(IMenuManager)を取得する方法がわかんない。いちおう
   WorkbenchWindow activeWorkbenchWindow = (WorkbenchWindow) PlatformUI
                .getWorkbench().getActiveWorkbenchWindow();
   IMenuManager menuManager = activeWorkbenchWindow.getActionBars()
                .getMenuManager();
でいけるけど、WorkbenchWindow が internalなんだよね。  -- [[きの]] &new{2006-03-02 22:16:08 (木)};

#comment
#topicpath


SIZE(10){現在のアクセス:&counter;}


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS