Eclipse/RCPのメニューバーの構築は、以下の2つの方法で行うことができます。
TUTORIALS 26 Developing for the Rich Client Platform によると
となっていますね。
さて、スケルトンとなる最小の構成をEclipse/RCPのフレームワークで作ります。
RCPは
IPlatformRunnable -> WorkbenchAdvisor -> WorkbenchWindowAdvisor -> ActionBarAdvisor
(の実装クラス)という順番に呼び出されるパタンになっていて、メニューバーはこの
org.eclipse.ui.application.ActionBarAdvisor
内の
protected void makeActions(IWorkbenchWindow window); protected void fillMenuBar(IMenuManager menuBar) ;
をOverrideすることで実装します。
ここでは下記のように実装しました。
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; } }
これで、以下のようにメニューバーが構築されました。
[ワークベンチ] | |-[File] | -[終了] | |-[Help] | -[検索] | -[○○について]
ポイントは
quitAction = ActionFactory.QUIT.create(window); <- 終了などActionFactory?から取得できる
がワークベンチのメニューバーのインスタンスなので、そこにアクションをaddしていく
などです。
さて、先のコードで、
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" | -[○○について] -
この場合、"セパレータ"部分は、正式名称*1は
help/group01 (メニュー名/グループ名)
となります。この名称を、拡張ポイントでアクションを追加するときに使用するわけです。
では先の"セパレータ"部分にアクションを追加します。セパレータの完全修飾メニュー・パスは
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の箇所に "追加アクション。" というアクションが追加されました。
図で書くと以下の通りですね。
[ワークベンチ] | |-[File] - "file" <- IWorkbenchActionConstants.M_FILE | -[終了] | |-[Help] - "help" <- IWorkbenchActionConstants.M_HELP | -[検索] | -"セパレータ" - "group01" | -[追加アクション。] - <- plugin.xmlで追加 | -[○○について] -
このように、セパレータなどを用いて、提供側の開発者がメニューを追加できるように「開いておいてくれた」場合、他のプラグイン開発者は、完全修飾メニュー・パスを知ることで容易にアクションを追加することができるわけですね。
次に、サブメニューを追加したいと思います。具体的には次のようにしたいと思います。
[ワークベンチ] | |-[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"
によって、先のサブメニューの下のセパレータ部分にこのアクションが挿入されることになります。
続いて以下のように複数のアクションを追加しました。
<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で追加 | -[○○について] -
となりました。
さらに以下の内容をplugin.xmlに追加します。
<action id="nu.mine.kino.plugin.samples.rcp.action3" label="追加アクション3" menubarPath="help/hogehoge" <- 存在しない完全修飾メニュー・パス />
すると
一番下に追加されました。
次に、以下のような階層的なメニュー構造を作ってみたいと思います。
[ワークベンチ] | |-[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で追加 | -[○○について] -
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>
となるわけです。
トップレベルのメニュー(ワークベンチが保持する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.メニューバー、ツールバーとアクションの紐付け(アクションの登録)
Eclipseでトップレベルにメニューを追加するといちばん右ではなく、途中の箇所にメニューが追加されますが、これはRCPとしてのEclipseが、その箇所にGroupMarker?を仕込んでくれているからです。グループマーカはメニュー内だけでなく、トップメニューでも使用できるようです。具体的には
org.eclipse.ui.internal.ide.WorkbenchActionBuilder
がEclipseのメニューバーを構築しているのですが、そのメソッドfillMenuBarでは
protected void fillMenuBar(IMenuManager menuBar) { menuBar.add(createFileMenu()); menuBar.add(createEditMenu()); menuBar.add(createNavigateMenu()); menuBar.add(createProjectMenu()); menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); menuBar.add(createWindowMenu()); menuBar.add(createHelpMenu()); }
となっていて、プロジェクトとウィンドウの間に
new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS);
が仕込まれています。で、このキー値をplugin.xmlに指定すれば、この場所にメニューが追加されます。*2
実際にさっきのサンプルでもやってみましょう。 ApplicationActionBarAdvisor?#fillMenuBar を以下のように変更します。
protected void fillMenuBar(IMenuManager menuBar) { menuBar.add(createFileMenu()); menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); menuBar.add(createHelpMenu()); ↑追加 }
さて、この IWorkbenchActionConstants?.MB_ADDITIONS というキー値は、実際の値はadditionsなので、
<menu id="topmenu" label="トップメニュー" path="additions"> <-追加 <groupMarker name="sepa01"/> </menu> <action id="nu.mine.kino.plugin.samples.rcp.action1" label="アクション。" menubarPath="topmenu/sepa01" style="push"/> </actionSet>
としておけばGroupMarker?の箇所にメニューが追加されます。
さて、実はIWorkbenchActionConstants?.MB_ADDITIONS(値はadditions)は定数定義されているとおり、デフォルト値?という特別な意味があるみたいです。よってplugin.xmlでpath属性を指定しなかった場合はadditionsを指定したことになるみたい。なので、実はpath="additions" を追加しないでも、グループマーカのところにメニューは表示されるのでした。
もちろん、
menuBar.add(new GroupMarker("hoge"));
としてplugin.xmlを path="hoge" とすると、グループマーカのところのそのメニューが表示されます。よってRCPのプロバイダ側は開いておきたいところにグループマーカを設定しておけばよいわけですね。
<separator name="sepa01"/>と<groupMarker name="sepa01"/>
の違いや
menu.add(new Separator("group01")); menu.add(new GroupMarker("group01"));
の違いについてですが、Separatorは違うグループ殿間に「セパレータ」が入るのに対し、GroupMarker?は入らない、という違いがあります。表示順を緻密に制御したい場合にGroupmMarker?を細かく入れて、そこにアクションをひもづける、なんて使い道があるんですね。
プラグイン開発のTIPS集/org.eclipse.ui.IWorkbenchWindowActionDelegate も参照ください。
この記事は
WorkbenchWindow activeWorkbenchWindow = (WorkbenchWindow) PlatformUI .getWorkbench().getActiveWorkbenchWindow(); IMenuManager menuManager = activeWorkbenchWindow.getActionBars() .getMenuManager();でいけるけど、WorkbenchWindow? が internalなんだよね。 -- きの? 2006-03-02 22:16:08 (木)
現在のアクセス:18798