在nebula中,官方默认提供了一个构造natTable的builder类,并且提供了一个debugInfo的默认右键菜单,但是当我们通过官方提供的builder去创建natTable,并且要添加多个右键菜单的时候,显得就不太灵活了,需要自己动手改改了,直接上代码吧:
1、创建一个抽象的菜单类AbstractMenuConfiguration:
1 public abstract class AbstractMenuConfiguration implements IMenuItemProvider { 2 3 private final String NAT_EVENT_DATA_KEY = "natEventData"; //$NON-NLS-1$ 4 5 @Override 6 public void addMenuItem(NatTable natTable, Menu popupMenu) { 7 MenuItem inspectLabelsMenuItem = new MenuItem(popupMenu, SWT.PUSH); 8 inspectLabelsMenuItem.setText(getMenuName()); 9 inspectLabelsMenuItem.setEnabled(true); 10 inspectLabelsMenuItem.addSelectionListener(new SelectionAdapter() { 11 @Override 12 public void widgetSelected(SelectionEvent e) { 13 processEvent(getNatEventData(e)); 14 } 15 }); 16 } 17 18 private NatEventData getNatEventData(SelectionEvent selectionEvent) { 19 Widget widget = selectionEvent.widget; 20 if (widget == null || !(widget instanceof MenuItem)) { 21 return null; 22 } 23 24 MenuItem menuItem = (MenuItem) widget; 25 Menu parentMenu = menuItem.getParent(); 26 Object data = null; 27 while (parentMenu != null) { 28 if (parentMenu.getData(this.NAT_EVENT_DATA_KEY) == null) { 29 parentMenu = parentMenu.getParentMenu(); 30 } else { 31 data = parentMenu.getData(this.NAT_EVENT_DATA_KEY); 32 break; 33 } 34 } 35 36 return data != null ? (NatEventData) data : null; 37 } 38 39 protected abstract void processEvent(NatEventData natEventData); 40 41 protected abstract String getMenuName(); 42 }
2、创建一个自定义PopupMenu构建类CustomerPopupMenuBuilder:
1 public class CustomerPopupMenuBuilder { 2 3 /** 4 * The active NatTable instance the context menu should be added to. Needed 5 * in advance to be able to add custom menu items that need the NatTable 6 * instance. 7 */ 8 protected NatTable natTable; 9 10 /** 11 * The {@link Menu} that is created with this popup menu builder. 12 */ 13 protected Menu popupMenu; 14 15 /** 16 * The {@link MenuManager} that is used by this popup menu builder. Can be 17 * <code>null</code> if plain SWT menu mechanisms are used. 18 */ 19 protected MenuManager menuManager; 20 21 /** 22 * Collection of all registered visibility state checkers for configured 23 * id's. 24 */ 25 protected final MenuItemStateMap visibility = new MenuItemStateMap(); 26 27 /** 28 * Collection of all registered enablement state checkers for configured 29 * id's. 30 */ 31 protected final MenuItemStateMap enablement = new MenuItemStateMap(); 32 33 /** 34 * Creates {@link CustomerPopupMenuBuilder} that builds up a new 35 * {@link Menu} that is only configurable with this instance of 36 * {@link CustomerPopupMenuBuilder}. Uses a {@link MenuManager} internally 37 * to be able to configure visibility and enabled states. 38 * 39 * @param parent 40 * The active NatTable instance the context menu should be added 41 * to. 42 */ 43 public CustomerPopupMenuBuilder(NatTable parent) { 44 this(parent, new MenuManager()); 45 } 46 47 /** 48 * Creates a {@link CustomerPopupMenuBuilder} that builds up a new 49 * {@link Menu} using the given {@link MenuManager}. 50 * 51 * @param parent 52 * The active NatTable instance the context menu should be added 53 * to. 54 * @param manager 55 * The {@link MenuManager} that should be used to create the 56 * {@link Menu}. 57 */ 58 public CustomerPopupMenuBuilder(NatTable parent, MenuManager manager) { 59 this.natTable = parent; 60 this.menuManager = manager; 61 this.popupMenu = manager.createContextMenu(this.natTable); 62 } 63 64 /** 65 * Creates a popup menu builder based on the given menu. Using this enables 66 * the possibility to use configured context menus from plugin.xml and 67 * adding NatTable commands programmatically. 68 * <p> 69 * As an example you might want to create a PopupMenuBuilder by using a 70 * configured menu with the id 71 * <i>org.eclipse.nebula.widgets.nattable.example.contextmenu</i> 72 * <p> 73 * 74 * <pre> 75 * ISelectionProvider isp = 76 * new RowSelectionProvider<?>(selectionLayer, bodyDataProvider, false); 77 * MenuManager menuManager = new MenuManager(); 78 * menuManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); 79 * getSite().registerContextMenu( 80 * "org.eclipse.nebula.widgets.nattable.example.contextmenu", menuManager, isp); 81 * PopupMenuBuilder popupMenu = 82 * new PopupMenuBuilder(menuManager.createContextMenu(natTable)); 83 * </pre> 84 * <p> 85 * For usage with Eclipse 4 you can use the <code>EMenuService</code> to 86 * register the menu to a NatTable instance. Afterwards get the menu and 87 * remove it from the NatTable to avoid the SWT control menu. The generated 88 * menu carries a {@link MenuManager} in the {@link Menu#getData()} which 89 * will be used within this {@link CustomerPopupMenuBuilder}. 90 * </p> 91 * 92 * <pre> 93 * menuService.registerContextMenu(natTable, menuId); 94 * Menu swtMenu = natTable.getMenu(); 95 * natTable.setMenu(null); 96 * </pre> 97 * 98 * @param natTable 99 * The active NatTable instance which might be needed for 100 * creation of menu items that need the NatTable instance to 101 * work. 102 * @param menu 103 * The registered context menu. 104 */ 105 public CustomerPopupMenuBuilder(NatTable natTable, Menu menu) { 106 this.natTable = natTable; 107 this.popupMenu = menu; 108 109 // if the menu is build up using a MenuManager, remember that for 110 // further use 111 if (menu.getData() != null && menu.getData() instanceof MenuManager) { 112 this.menuManager = (MenuManager) menu.getData(); 113 } 114 } 115 116 /** 117 * Adds the menu item provided by the given {@link IMenuItemProvider} to the 118 * popup menu. You can use this to add your own item to the popup menu. 119 * <p> 120 * Items added by this method can not be identified by id, so adding visible 121 * or enabled state checkers is not possible for these providers. 122 * </p> 123 * 124 * @param menuItemProvider 125 * The {@link IMenuItemProvider} that provides the menu item that 126 * should be added to the popup menu. 127 * @return The current {@link CustomerPopupMenuBuilder} with the added item. 128 */ 129 public CustomerPopupMenuBuilder withMenuItemProvider(IMenuItemProvider menuItemProvider) { 130 if (this.menuManager == null) { 131 menuItemProvider.addMenuItem(this.natTable, this.popupMenu); 132 } else { 133 this.menuManager.add(new PopupContributionItem(menuItemProvider)); 134 } 135 return this; 136 } 137 138 /** 139 * Adds the menu item provided by the given {@link IMenuItemProvider} to the 140 * popup menu. You can use this to add your own item to the popup menu. 141 * <p> 142 * As items added by this method can be identified via the given id it is 143 * possible to register visible or enabled state checkers for these 144 * providers. 145 * </p> 146 * 147 * @param id 148 * The id under which the given {@link IMenuItemProvider} should 149 * be identifiable. 150 * @param menuItemProvider 151 * The {@link IMenuItemProvider} that provides the menu item that 152 * should be added to the popup menu. 153 * @return The current {@link CustomerPopupMenuBuilder} with the added item. 154 */ 155 public CustomerPopupMenuBuilder withMenuItemProvider(String id, IMenuItemProvider menuItemProvider) { 156 if (this.menuManager == null) { 157 menuItemProvider.addMenuItem(this.natTable, this.popupMenu); 158 } else { 159 this.menuManager.add(new PopupContributionItem(id, menuItemProvider)); 160 } 161 return this; 162 } 163 164 /** 165 * Adds the menu item(s) provided by the given {@link ContributionItem} to 166 * the popup menu. You can use this to add your own item to the popup menu. 167 * <p> 168 * This method is only working if the {@link CustomerPopupMenuBuilder} is 169 * using a {@link MenuManager}. 170 * </p> 171 * <p> 172 * Using this adds support for visibility and enabled states of menu items. 173 * </p> 174 * 175 * @param contributionItem 176 * The {@link ContributionItem} that is used to add a menu item 177 * to the menu. 178 * @return The current {@link CustomerPopupMenuBuilder} with the added item. 179 * @throws IllegalStateException 180 * if this {@link CustomerPopupMenuBuilder} does not use a 181 * {@link MenuManager} 182 */ 183 public CustomerPopupMenuBuilder withContributionItem(ContributionItem contributionItem) { 184 if (this.menuManager == null) { 185 throw new IllegalStateException("This PopupMenuBuilder is not created using a MenuManager, " //$NON-NLS-1$ 186 + "therefore ContributionItems can not be added"); //$NON-NLS-1$ 187 } else { 188 this.menuManager.add(contributionItem); 189 } 190 return this; 191 } 192 193 public CustomerPopupMenuBuilder configureMenuItemProvider(String mid, IMenuItemProvider menuItemProvider) { 194 return withMenuItemProvider( 195 mid, 196 menuItemProvider); 197 } 198 199 /** 200 * Adds a separator to the popup menu with the given id. 201 * 202 * @param id 203 * The id to identify the separator. Necessary if there should be 204 * visibility constraints for specific separators. 205 * @return The {@link CustomerPopupMenuBuilder} with an added separator. 206 * @see MenuItemProviders#separatorMenuItemProvider() 207 */ 208 public CustomerPopupMenuBuilder withSeparator(String id) { 209 return withMenuItemProvider(id, MenuItemProviders.separatorMenuItemProvider()); 210 } 211 212 /** 213 * Builds and returns the created {@link Menu}. 214 * <p> 215 * <b>Note:</b> Calling this method will also add a {@link DisposeListener} 216 * to the NatTable instance to ensure the created {@link Menu} is disposed 217 * when the NatTable itself gets disposed. 218 * </p> 219 * 220 * @return The {@link Menu} that is created by this builder. 221 */ 222 public Menu build() { 223 224 this.natTable.addDisposeListener(new DisposeListener() { 225 @Override 226 public void widgetDisposed(DisposeEvent e) { 227 if (CustomerPopupMenuBuilder.this.popupMenu != null 228 && !CustomerPopupMenuBuilder.this.popupMenu.isDisposed()) 229 CustomerPopupMenuBuilder.this.popupMenu.dispose(); 230 } 231 }); 232 233 return this.popupMenu; 234 } 235 236 /** 237 * Associate a visibility {@link IMenuItemState} with the menu item 238 * identified by the given id. 239 * <p> 240 * The visibility state is handled by the internal {@link MenuManager}. If 241 * no {@link MenuManager} is used, this method will have not effect. 242 * </p> 243 * <p> 244 * For the item to be visible, all associated {@link IMenuItemState} must be 245 * active OR no {@link IMenuItemState} must be associated with the item. 246 * </p> 247 * 248 * @param id 249 * the registered {@link IMenuItemState} will affect the menu 250 * item identified by the given id. 251 * @param state 252 * the {@link IMenuItemState} to queried for the visibility state 253 * of the menu item with the given id. 254 * @return This {@link CustomerPopupMenuBuilder} with the visible state 255 * checker for the given id. 256 */ 257 public CustomerPopupMenuBuilder withVisibleState(String id, IMenuItemState state) { 258 this.visibility.addMenuItemState(id, state); 259 return this; 260 } 261 262 /** 263 * Associate a enabled {@link IMenuItemState} with the menu item identified 264 * by the given id. 265 * <p> 266 * The enabled state is handled by the internal {@link MenuManager}. If no 267 * {@link MenuManager} is used, this method will have not effect. 268 * </p> 269 * <p> 270 * For the item to be enabled, all associated {@link IMenuItemState} must be 271 * active OR no {@link IMenuItemState} must be associated with the item. 272 * </p> 273 * 274 * @param id 275 * the registered {@link IMenuItemState} will affect the menu 276 * item identified by the given id. 277 * @param state 278 * the {@link IMenuItemState} to queried for the enabled state of 279 * the menu item with the given id. 280 * @return This {@link CustomerPopupMenuBuilder} with the enabled state 281 * checker for the given id. 282 */ 283 public CustomerPopupMenuBuilder withEnabledState(String id, IMenuItemState state) { 284 this.enablement.addMenuItemState(id, state); 285 return this; 286 } 287 288 /** 289 * Wrapper class to build up a {@link ContributionItem} based on a given 290 * {@link IMenuItemProvider}. If an id is set it is possible to register 291 * state checkers for enabled and visible state. 292 */ 293 protected class PopupContributionItem extends ContributionItem { 294 295 private IMenuItemProvider provider; 296 297 public PopupContributionItem(IMenuItemProvider provider) { 298 this(null, provider); 299 } 300 301 public PopupContributionItem(String id, IMenuItemProvider provider) { 302 super(id); 303 this.provider = provider; 304 } 305 306 @Override 307 public void fill(Menu menu, int index) { 308 List<MenuItem> beforeItems = Arrays.asList(menu.getItems()); 309 this.provider.addMenuItem(CustomerPopupMenuBuilder.this.natTable, menu); 310 MenuItem[] afterItems = menu.getItems(); 311 312 for (MenuItem item : afterItems) { 313 if (!beforeItems.contains(item)) { 314 // isEnabled() seems to be not called by the framework on 315 // opening a menu therefore we set it ourself. For this we 316 // also need to ensure isDynamic() returns true for 317 // re-rendering. 318 item.setEnabled(isEnabled()); 319 } 320 } 321 } 322 323 @Override 324 public boolean isDynamic() { 325 return (getId() != null); 326 } 327 328 @Override 329 public boolean isEnabled() { 330 if (getId() != null) { 331 Object eventData = CustomerPopupMenuBuilder.this.popupMenu.getData(MenuItemProviders.NAT_EVENT_DATA_KEY); 332 if (eventData != null && eventData instanceof NatEventData) { 333 return CustomerPopupMenuBuilder.this.enablement.isActive(getId(), (NatEventData) eventData); 334 } 335 } 336 return true; 337 } 338 339 @Override 340 public boolean isVisible() { 341 if (getId() != null) { 342 Object eventData = CustomerPopupMenuBuilder.this.popupMenu.getData(MenuItemProviders.NAT_EVENT_DATA_KEY); 343 if (eventData != null && eventData instanceof NatEventData) { 344 return CustomerPopupMenuBuilder.this.visibility.isActive(getId(), (NatEventData) eventData); 345 } 346 } 347 return true; 348 } 349 350 } 351 }
3、实现自定义多右键菜单配置CustomerPopupMenuConfiguration:
1 public class CustomerPopupMenuConfiguration extends AbstractUiBindingConfiguration { 2 3 private Menu menu; 4 5 private CustomerPopupMenuBuilder customerPopupMenuBuilder; 6 7 public CustomerPopupMenuConfiguration(NatTable natTable) { 8 this.customerPopupMenuBuilder = new CustomerPopupMenuBuilder(natTable); 9 10 } 11 12 public CustomerPopupMenuConfiguration configureMenuItemProvider(String mid, IMenuItemProvider menuItemProvider) { 13 this.customerPopupMenuBuilder.configureMenuItemProvider(mid, menuItemProvider); 14 return this; 15 } 16 17 public CustomerPopupMenuConfiguration build() { 18 this.menu = this.customerPopupMenuBuilder.build(); 19 return this; 20 } 21 22 @Override 23 public void configureUiBindings(UiBindingRegistry uiBindingRegistry) { 24 uiBindingRegistry.registerMouseDownBinding( 25 new MouseEventMatcher(SWT.NONE, null, 3), 26 new PopupMenuAction(this.menu)); 27 } 28 }
4、后面剩下的就是怎么使用自定义菜单了配置了:
1 public class Test{ 2 public void configure(NatTable natTable){ 3 ...... 4 natTable.addConfiguration(new CustomerPopupMenuConfiguration(natTable).configureMenuItemProvider("addRowMenuItem", new AbstractMenuConfi guration(){ 5 @Override 6 protected String getMenuName() { 7 return "add"; 8 } 9 @Override 10 protected void processEvent(NatEventData natEventData) { 11 //处理增加 12 } 13 }).configureMenuItemProvider("updateRowMenuItem", new AbstractMenuConfiguration(){ 14 @Override 15 protected String getMenuName() { 16 return "update"; 17 } 18 @Override 19 protected void processEvent(NatEventData natEventData) { 20 // 处理修改 21 } 22 }).configureMenuItemProvider("deleteRowMenuItem", new AbstractMenuConfiguration(){ 23 @Override 24 protected String getMenuName() { 25 return "delete"; 26 } 27 @Override 28 protected void processEvent(NatEventData natEventData) { 29 //处理删除 30 } 31 }).build()); 32 ..... 33 } 34 }
以上就实现了灵活自定义右键菜单。