如何让natTable表格支持自定义多个右键菜单

在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&lt;?&gt;(selectionLayer, bodyDataProvider, false);
 77      * MenuManager menuManager = new MenuManager();
 78      * menuManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
 79      * getSite().registerContextMenu(
 80      *         &quot;org.eclipse.nebula.widgets.nattable.example.contextmenu&quot;, 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 }

以上就实现了灵活自定义右键菜单。

原文地址:https://www.cnblogs.com/jessezeng/p/5070913.html