如何为XML生成的Eclipse菜单添加MenuListener监听焦点事件
Question
I've defined a menu in my Eclipse plug-in using the org.eclipse.ui.editorActions extension point, as shown below. How can I add a MenuListener to this menu so that I can run code when the menu receives focus (before it's clicked)?
<extension point="org.eclipse.ui.editorActions"> <editorContribution targetID="net.sourceforge.texlipse.TexEditor" id="net.sourceforge.texlipse.editor.editorContribution"> <menu label="&TTS Settings" id="net.sourceforge.texlipse.menus.tts"> <separator name="sourceGroup"/> <separator name="latexGroup"/> <separator name="commentGroup"/> <separator name="spellGroup"/> </menu> <action class="net.sourceforge.texlipse.actions.TTSPdfModeAction" icon="icons/start.png" id="net.sourceforge.texlipse.actions.TTSPdfModeAction" definitionId="net.sourceforge.texlipse.commands.PDF" label="&PDF" menubarPath="net.sourceforge.texlipse.menus.tts/sourceGroup" style="push" toolbarPath="latexGroup" tooltip="PDF"/> <action class="net.sourceforge.texlipse.actions.TTSStopAction" icon="icons/stop.png" id="net.sourceforge.texlipse.actions.TTSStopAction" definitionId="net.sourceforge.texlipse.commands.TTSStop" label="&Stop" menubarPath="net.sourceforge.texlipse.menus.tts/sourceGroup" style="push" toolbarPath="latexGroup" tooltip="Stop"/> </editorContribution> </extension>
Answer
Great question! Eclipse's plugin.xml doesn't support directly configuring MenuListeners for menus defined via extensions. Instead, you'll need to dynamically fetch the menu instance through code and attach the listener at the right time. Here's how to implement this:
1. Choose the Right Timing to Attach the Listener
The most reliable approach is to listen for when your target editor (TexEditor) is activated. This ensures you hook into the menu as soon as the editor is ready to use. We'll use an IPartListener2 to handle this event.
2. Retrieve the Menu Manager and Add the Listener
First, create a part listener class to handle editor activation and attach your menu listener:
import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.part.IPartListener2; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IActionBars; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.events.FocusAdapter; import org.eclipse.swt.events.FocusEvent; import org.eclipse.jface.action.IMenuListener; public class TexEditorMenuListener implements IPartListener2 { @Override public void partActivated(IWorkbenchPartReference partRef) { IWorkbenchPart part = partRef.getPart(true); // Check if the activated part is your TexEditor if (part instanceof net.sourceforge.texlipse.TexEditor) { IEditorPart editor = (IEditorPart) part; IActionBars actionBars = editor.getEditorSite().getActionBars(); // Get the main menu manager and find your TTS Settings menu by ID MenuManager mainMenu = (MenuManager) actionBars.getMenuManager(); IMenuManager ttsMenu = mainMenu.findMenuUsingPath("net.sourceforge.texlipse.menus.tts"); if (ttsMenu != null) { // Add a MenuListener to trigger when the menu is about to show (focused but not clicked) ttsMenu.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager manager) { // This runs when the menu receives focus (mouse hover or keyboard navigation) System.out.println("TTS Settings menu focused - running pre-click logic"); // Add your custom operations here (e.g., update menu state, load data) } }); // Optional: Listen for focus on individual menu items // Note: The Menu control is only created after the menu is first opened ttsMenu.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager manager) { Menu menu = ((MenuManager) manager).getMenu(); if (menu != null) { for (int i = 0; i < menu.getItemCount(); i++) { MenuItem item = menu.getItem(i); item.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { // Trigger when a specific menu item gains focus System.out.println("Menu item focused: " + item.getText()); // Add your item-specific logic here } }); } } } }); } } } // Implement other IPartListener2 methods with empty bodies (or add logic if needed) @Override public void partBroughtToTop(IWorkbenchPartReference partRef) {} @Override public void partClosed(IWorkbenchPartReference partRef) {} @Override public void partDeactivated(IWorkbenchPartReference partRef) {} @Override public void partHidden(IWorkbenchPartReference partRef) {} @Override public void partOpened(IWorkbenchPartReference partRef) {} @Override public void partVisible(IWorkbenchPartReference partRef) {} @Override public void partInputChanged(IWorkbenchPartReference partRef) {} }
3. Register the Part Listener in Your Plugin Activator
Add this listener to your plugin's activator class so it runs when the plugin starts:
import org.eclipse.ui.PlatformUI; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.osgi.framework.BundleContext; public class Activator extends AbstractUIPlugin { private static Activator plugin; @Override public void start(BundleContext context) throws Exception { super.start(context); plugin = this; // Register the part listener to monitor editor activation PlatformUI.getWorkbench().getActiveWorkbenchWindow().getPartService().addPartListener(new TexEditorMenuListener()); } @Override public void stop(BundleContext context) throws Exception { plugin = null; super.stop(context); } public static Activator getDefault() { return plugin; } }
Key Notes
- Menu vs. Menu Item Focus: The
menuAboutToShowmethod triggers when the menu itself receives focus (e.g., mouse hover, keyboard navigation to the menu). If you need to track focus on individual menu items, use theFocusListenerapproach shown above (remember the Menu control only exists after the menu is first opened). - Avoid Duplicate Listeners: If you want to prevent adding the listener multiple times when the editor is activated repeatedly, add a check to see if the listener is already attached before adding it.
内容的提问来源于stack exchange,提问作者user3820414

