基于所选节点的 TreeViewer 上下文菜单 - SWT

Posted

技术标签:

【中文标题】基于所选节点的 TreeViewer 上下文菜单 - SWT【英文标题】:Context menu for TreeViewer based on selected node - SWT 【发布时间】:2011-09-06 15:47:25 【问题描述】:

我需要在 Eclipse 插件项目中为 TreeViewer 创建一个上下文菜单。但是,菜单不应包含常量项,它们应根据所选节点的类型而有所不同。例如,我的 treeViewer 具有以下层次结构:

Node A
 |
 --Node B
  |
   --Node C

对于节点 A - 我想显示一个带有操作的菜单,但对于节点 B 和 C,我不想显示任何内容(无菜单)。 I managed to create the menu for node A, but then I can't get rid of it when some other type of node is selected.我的代码如下:

treeViewer.addSelectionChangedListener(
            new ISelectionChangedListener()
                public void selectionChanged(SelectionChangedEvent event) 
                    if(event.getSelection() instanceof IStructuredSelection) 
                        IStructuredSelection selection = (IStructuredSelection)event.getSelection();            
                        Object o = selection.getFirstElement();     

                        MenuManager menuMgr = new MenuManager();

                        if (o instanceof NodeA)

                            Menu menu = menuMgr.createContextMenu(treeViewer.getControl());
                            treeViewer.getControl().setMenu(menu);
                            getSite().registerContextMenu(menuMgr, treeViewer);

                            menuMgr.add(new SomeAction());

                        else 
                            //what ?
                        
                    

                
               
    );

在 else 分支上,我尝试在 MenuManager 上调用 dispose(),removeAll()...没有任何效果!

感谢任何帮助,谢谢。

【问题讨论】:

【参考方案1】:

只需使用单个菜单管理器。 不要动态制作菜单管理器。

理论上,你有可能尝试过,但效率低下,也不是一般的方法。

只需创建一个菜单管理器并添加您需要的所有操作。

选择已更改时,调用操作#setvisible(true | false)隐藏或显示菜单项。 您还可以使用 Action#setEnable 来启用/禁用菜单项。

ps。 菜单管理器不是菜单 GUI(就像 TreeViewer 不是树)

它将操作(业务逻辑)贡献给菜单(SWT)。它还管理可见性和启用。我们称之为贡献经理。我们可以很容易地创建一个 SWT 菜单。 (即使我们不知道 SWT,我们只需要知道我们的业务逻辑:Action)它是 JFace 中的基本思想。

当你在manu manager中添加一个action时,action会被ActionContributionItem包裹起来。它挂钩动作的状态以更新 UI(可见性、菜单、按钮、工具栏等的启用)。它还挂钩 UI 以在按下时启动操作。

如果你是 eclipse 新手,很容易混淆 SWT 和 JFace 的角色。

【讨论】:

感谢您的提示,现在我只创建一次菜单,然后在进行选择时调用 action.setEnabled(false)。这工作正常,但我没有找到用于 Action 的 setVisible 方法。我想在选择其他节点时将其隐藏,而不是使其变灰。谢谢 如果您添加包含您的操作的ActionContributionItems,它们有一个setVisible(boolean) 方法。但是您应该选择setRemoveAllWhenShown(*) 或更新ActionContributionItems 的可见性,因为它们是不同的方法。【参考方案2】:

正如@jeeeyul 提到的,您应该只创建一个 MenuManager 以在您的视图中使用。

您可以使用 New>Plug-in Project 和视图模板在使用查看器的视图中获取上下文菜单的示例,但基本上在您的 createPartControl(Composite) 方法中,您将连接您的上下文管理器。

    MenuManager menuMgr = new MenuManager();
    menuMgr.setRemoveAllWhenShown(true);
    menuMgr.addMenuListener(new IMenuListener() 
        public void menuAboutToShow(IMenuManager manager) 
            SampleView.this.fillContextMenu(manager);
        
    );
    Menu menu = menuMgr.createContextMenu(viewer.getControl());
    viewer.getControl().setMenu(menu);
    getSite().registerContextMenu(menuMgr, viewer);

您的fillContextMenu(MenuManager) 方法将可以访问您的查看器,因此您可以从中获取当前选择。您可以添加任何您想要的操作,甚至在使用当前选择更新它们后重新添加操作。

registerContextMenu(*) 调用允许 org.eclipse.ui.popupMenus 和 org.eclipse.ui.menus 等扩展点向上下文菜单添加项目。

【讨论】:

是的,我现在正在使用这种方法。在我的其他观点中,我只创建了一次这样的。但我真正关心的是如何更改菜单的内容。 fillContextMenu(*) 在每个菜单 SWT.Show 事件上调用。您可以在该方法中每次更改菜单的内容。【参考方案3】:

我就是这样做的:

MenuManager menuMgr = new MenuManager();

        Menu menu = menuMgr.createContextMenu(viewer.getControl());
        menuMgr.addMenuListener(new IMenuListener() 
            @Override
            public void menuAboutToShow(IMenuManager manager) 
                // IWorkbench wb = PlatformUI.getWorkbench();
                // IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
                if (viewer.getSelection().isEmpty()) 
                    return;
                

                if (viewer.getSelection() instanceof IStructuredSelection) 
                    IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
                    Node object = (Node)selection.getFirstElement();

                    if (object.getModel() instanceof NodeA) 
                        manager.add(new Action();
                     else if (object.getModel() instanceof NodeB) 

                        manager.add(new OtherAction());

                    
                
            
        );
        menuMgr.setRemoveAllWhenShown(true);
        viewer.getControl().setMenu(menu);

我希望这会有所帮助;)

将菜单管理器的 removeAllWhenShown 属性设置为 false 很重要,以便隐藏所有其他节点的操作;)

【讨论】:

【参考方案4】:

假设你知道如何创建动作并且你只对上下文菜单感兴趣,下面的例子对我有用,希望这堆代码对你有帮助

 private void hookContextMenu() 
    MenuManager contextMenu = new MenuManager();
    contextMenu.setRemoveAllWhenShown(true);
    contextMenu.addMenuListener(new IMenuListener() 

        @Override
        public void menuAboutToShow(IMenuManager manager) 



            IStructuredSelection sSelection = (IStructuredSelection) treeViewer.getSelection();

            
            if(selectedObject instanceof A)
            manager.add(action);
            

        
    );

【讨论】:

以上是关于基于所选节点的 TreeViewer 上下文菜单 - SWT的主要内容,如果未能解决你的问题,请参考以下文章

如何获取所选列表视图项中的id以打开上下文菜单并通过下一个活动来实现目标。

Django CMS:基于所选插件的页面内导航菜单

查找在上下文菜单下单击的节点

根据所选列表视图项的位置设置铃声

基于所选货币的运输限制

QT 模型/视图编程:我应该如何检索上下文菜单选项的额外数据?