分类:
2009-08-04 23:28:39
------------------------------------------------
本文系本站原创,欢迎转载!
估计大家在用eclipse开发桌面程序时,第一堂课就得接触menu,toolbar,估计大家也已经接触到了几种添加方式,下面我将详细解释eclipse中创建菜单或工具栏项的各种方式及如何创建动态菜单和隐藏在eclipse部件中和菜单有关的一些秘密。
先讲几种创建菜单的方式。
第一种:
通过action.
这种方式一般就是在这个就是先创建action,然后将action添加到menumanger
所以一般是通过makeaction创建action,然后通过fillMenuBar,fillToolBar将action添加。
第二种:
扩展点方式:
这种方式估计是大家最早接触的,这种方式是通过添加org.eclipse.ui.actionSets
扩展点。
这种方式简单,但是添加的action要继承IWorkbenchWindowActionDelegate
其实这种方式,也是通过action,系统根据扩展点信息,生成一个action ,同时根据其他信息,如name,icon,调用setText(),setImageDescriptor()设置,但是这个action的run很特殊,它就是根据class id,创建对应的IWorkbenchWindowActionDelegate实例,然后调用这个的run ,其实这个过程就是代理的工作方式,所以IWorkbenchWindowActionDelegate的delegate词很有道理。
要创建动态菜单,其实只要添加菜单的事件监听Listener即可:
代码如下:
@Override
public void fillContextMenu(IMenuManager mgr) {
MenuManager menuManager = (MenuManager) mgr;
menuManager.setRemoveAllWhenShown(true);
//这个就是定义菜单显示的时候先清空
menuManager.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
fillMenu(manager);
//监听到要显示事件后,重新填充菜单,这样就可以达到动态效果,因为每次打开都要重新填充菜单。
}
});
Tree tree = tv.getTree();
Menu menu = menuManager.createContextMenu(tree);
tree.setMenu(menu);
}
就比如当我打开一个编辑器时,会出现一个菜单项,但是当编辑器关闭时,菜单项就消失了,这个就不是上面能够实现的了。
这个可以通过添加editor的contributorclass实现,这个类最好继承ActionBarContributor,然后通过contributeToToolBar, contributeToToolBar, contributeToCoolBar添加菜单,这样添加的菜单就是随着editor而生而死的。
public class DiagramActionBarContributor extends ActionBarContributor {
protected void buildActions() {
// TODO Auto-generated method stub
addRetargetAction(new UndoRetargetAction());
addRetargetAction(new RedoRetargetAction());
addRetargetAction(new DeleteRetargetAction());
}
public void contributeToToolBar(IToolBarManager toolBarManager){
toolBarManager.add(getAction(ActionFactory.UNDO.getId()));
toolBarManager.add(getAction(ActionFactory.REDO.getId()));
toolBarManager.add(getAction(ActionFactory.DELETE.getId()));
}
public void contributeToMenu(IMenuManager menuManager) {
MenuManager drawMenu=new MenuManager("&Draw","Draw");
menuManager.add(drawMenu);
drawMenu.add(getAction(ActionFactory.UNDO.getId()));
drawMenu.add(getAction(ActionFactory.REDO.getId()));
drawMenu.add(getAction(ActionFactory.DELETE.getId()));
}
public void contributeToCoolBar(ICoolBarManager coolBar){
IToolBarManager toolbar=new ToolBarManager(SWT.FLAT|SWT.RIGHT);
coolBar.add(new ToolBarContributionItem(toolbar,"main"));
toolbar.add(getAction(ActionFactory.UNDO.getId()));
toolbar.add(getAction(ActionFactory.REDO.getId()));
toolbar.add(getAction(ActionFactory.DELETE.getId()));
}
}
也许你很想知道它的原理。
其实原理也很简单:
这些函数的参数IMenuManager menuManager其实是submenuManger,他由editor创建,然后editor 失效时就会remove,所以菜单就会消失。
protected void fillMenuBar(IMenuManager menuBar) {
SubMenuManager filemenu=new SubMenuManager(menuBar);
filemenu.setVisible(true);//必须,否则不会显示
// filemenu.setRemoveAllWhenShown(true);
//filemenu.add(diagramAction);
MenuManager filemenu1=new MenuManager("&File","File");
filemenu1.add(diagramAction);
filemenu.add(filemenu1);
// menuBar.add(filemenu);
}
通过filemenu.removeAll();就可删除菜单,达到动态的效果,其实editorpart的contributclass添加的菜单就是这样。
menuBar.remove(filemenu);用这种方法不行,为什么,因为其实只有filemenu知道menubar,而menubar不知道filemenu,在filemenu下添加的menumanger其实是通过filemenu添加到menubar上去了,所以menubar不知道filemenu的存在,但是知道filemenu下的东西的存在,当filemenu执行removeall,其实他是调用了它的parent,menubar的remove,从而达到清除目的。
public abstract class SubContributionManager implements
public void add(IContributionItem item) {
item.setParent(this);
SubContributionItem wrap = wrap(item);
wrap.setVisible(visible);
parentMgr.add(wrap);
itemAdded(item, wrap);
}
public IContributionItem remove(IContributionItem item) {
SubContributionItem wrap = (SubContributionItem) mapItemToWrapper
.get(item);
if (wrap == null) {
return null;
}
IContributionItem result = parentMgr.remove(wrap);
if (result == null) {
return null;
}
itemRemoved(item);
return item;
}
contributeClass就是
它主要是提供创建action及添加action到menubar,toolbar的接口。
添加接口就有好几个:
Addaction,addRetargetAction(然后在contributToMenuBar里通过register.getaction就可以获取)。Addaction添加的action就是一般的,而addRetargetAction添加的action很特别。它添加的是retargetaction类型的action,它其实也可以看成一个代理,它具有监听功能。这个action真正执行的时候是通过它的handler执行,这个handle就是一个action,所以关键是这个Handle如何赋值,这些Handle的值是通过id,调用editpart的register.getaction(id)获取,这样达到表示体和执行体分开的目的,其实和前面聊到通过扩展点添加菜单差不多的机理。
public class RetargetAction extends PartEventAction implements
ActionFactory.IWorkbenchAction {
public abstract class PartEventAction extends Action implements IPartListener
其中IPartListener挂载在workbenchpage上用来监听part的,
protected void addRetargetAction(RetargetAction action) {
addAction(action);
retargetActions.add(action);
getPage().addPartListener(action);
//监听
addGlobalActionKey(action.getId());
}
这样当有editpart或viewpart出来时,retargetaction就会检测到,
protected void propagateChange(PropertyChangeEvent event) {
if (event.getProperty().equals(IAction.ENABLED)) {
Boolean bool = (Boolean) event.getNewValue();
setEnabled(bool.booleanValue());
} else if (event.getProperty().equals(IAction.CHECKED)) {
Boolean bool = (Boolean) event.getNewValue();
setChecked(bool.booleanValue());
} else if (event.getProperty().equals(SubActionBars.P_ACTION_HANDLERS)) {
if (event.getSource() instanceof IActionBars) {
IActionBars bars = (IActionBars) event.getSource();
setActionHandler(bars.getGlobalActionHandler(getId()));
}
}
}
然后就绑定了。
Retarget是可以绑定到一个action的,这个就是他的handler,这个在
public void init(IActionBars bars) {
this.bars = bars;
contributeToMenu(bars.getMenuManager());
contributeToToolBar(bars.getToolBarManager());
if (bars instanceof IActionBars2) {
contributeToCoolBar(((IActionBars2) bars).getCoolBarManager());
}
contributeToStatusLine(bars.getStatusLineManager());
}
public void setActiveEditor(IEditorPart editor) {
ActionRegistry registry = (ActionRegistry)editor.getAdapter(ActionRegistry.class);
IActionBars bars = getActionBars();
for (int i = 0; i < globalActionKeys.size(); i++) {
String id = (String)globalActionKeys.get(i);
bars.setGlobalActionHandler(id, registry.getAction(id));
}
}
}
因为在Init中bars已经加入retargetaction,这样当能绑定了。
总结:
如果在contributeclass使用的是retargetaction,必须在editpart里注册对应id的action。
比如在contributeclass是:
addRetargetAction(new UndoRetargetAction());
那么在editpart里要有:
ActionRegistry registry = getActionRegistry();
IAction action;
action = new UndoAction(this);
registry.registerAction(action);
Undoaction和UndoRetargetAction的id是一样的,这样才配对的了。