Chinaunix首页 | 论坛 | 博客
  • 博客访问: 512777
  • 博文数量: 95
  • 博客积分: 5168
  • 博客等级: 大校
  • 技术积分: 1271
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-28 23:31
文章分类

全部博文(95)

文章存档

2013年(2)

2012年(3)

2011年(1)

2010年(8)

2009年(81)

分类:

2009-08-04 23:28:39

------------------------------------------------
本文系本站原创,欢迎转载!

转载请注明出处:http://sjj0412.cublog.cn/
------------------------------------------

  估计大家在用eclipse开发桌面程序时,第一堂课就得接触menu,toolbar,估计大家也已经接触到了几种添加方式,下面我将详细解释eclipse中创建菜单或工具栏项的各种方式及如何创建动态菜单和隐藏在eclipse部件中和菜单有关的一些秘密。

先讲几种创建菜单的方式。

第一种:

         通过action.

         这种方式一般就是在这个就是先创建action,然后将action添加到menumanger 

         所以一般是通过makeaction创建action,然后通过fillMenuBarfillToolBaraction添加。

第二种:

   扩展点方式:

   这种方式估计是大家最早接触的,这种方式是通过添加org.eclipse.ui.actionSets

扩展点。        

这种方式简单,但是添加的action要继承IWorkbenchWindowActionDelegate

其实这种方式,也是通过action,系统根据扩展点信息,生成一个action ,同时根据其他信息,如name,icon,调用setText(),setImageDescriptor()设置,但是这个actionrun很特殊,它就是根据class id,创建对应的IWorkbenchWindowActionDelegate实例,然后调用这个的run ,其实这个过程就是代理的工作方式,所以IWorkbenchWindowActionDelegatedelegate词很有道理。

  那如何创建动态菜单呢?

     要创建动态菜单,其实只要添加菜单的事件监听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);

}

这是动态显示菜单,那动态添加菜单呢

就比如当我打开一个编辑器时,会出现一个菜单项,但是当编辑器关闭时,菜单项就消失了,这个就不是上面能够实现的了。

这个可以通过添加editorcontributorclass实现,这个类最好继承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();就可删除菜单,达到动态的效果,其实editorpartcontributclass添加的菜单就是这样。

menuBar.remove(filemenu);用这种方法不行,为什么,因为其实只有filemenu知道menubar,menubar不知道filemenu,filemenu下添加的menumanger其实是通过filemenu添加到menubar上去了,所以menubar不知道filemenu的存在,但是知道filemenu下的东西的存在,当filemenu执行removeall,其实他是调用了它的parentmenubarremove,从而达到清除目的。

 

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:

       contributeClass就是

它主要是提供创建action及添加actionmenubar,toolbar的接口。

添加接口就有好几个:

Addaction,addRetargetAction(然后在contributToMenuBar里通过register.getaction就可以获取)。Addaction添加的action就是一般的,而addRetargetAction添加的action很特别。它添加的是retargetaction类型的action,它其实也可以看成一个代理,它具有监听功能。这个action真正执行的时候是通过它的handler执行,这个handle就是一个action,所以关键是这个Handle如何赋值,这些Handle的值是通过id,调用editpartregister.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());

}

这样当有editpartviewpart出来时,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));

    }

}

}

因为在Initbars已经加入retargetaction,这样当能绑定了。

总结:

如果在contributeclass使用的是retargetaction,必须在editpart里注册对应idaction

  比如在contributeclass是:

addRetargetAction(new UndoRetargetAction());

那么在editpart里要有:

ActionRegistry registry = getActionRegistry();

    IAction action;

   

    action = new UndoAction(this);

    registry.registerAction(action);

 

UndoactionUndoRetargetActionid是一样的,这样才配对的了。

 

 

阅读(2621) | 评论(0) | 转发(1) |
0

上一篇:armlinux第3天分析

下一篇:Eclipse菜单探密(2)

给主人留下些什么吧!~~