Search code examples
javaswingjmenuitemjpopupmenu

JPopupMenu know which JMenuItem are clicked


my question in very simple. I have a JPopupMenu that shown two JMenuItem. The only way I have found to know which item are clicked using

class MenuActionListener implements ActionListener {
  public void actionPerformed(ActionEvent e) {
    System.out.println("Selected: " + e.getActionCommand());    
  }
}

but the command e.getActionCommand() print the text inside the item. I would like get an index from 0 to n to known which item are clicked and not the text (that can be modified). Is it possible ?


Solution

  • You Could...

    Place each JMenuItem in a Map, with the int value you want

    Map<JMenuItem, Integer> menuMap = new HashMap<JMenuItem, Integer>(25);
    //...
    JMenuItem item1 = ...
    menuMap.put(item, 0);
    JMenuItem item2 = ...
    menuMap.put(item, 1);
    

    Then in the ActionListener, you would simply look it up based on the source of the event...

    public void actionPerformed(ActionEvent e) {
        JMenuItem item = (JMenuItem)e.getSource();
        int index = menuMap.get(item);
    

    You Could...

    Use a List and determine the index of the JMenuItem within the list...

    List<JMenuItem> menuList = new ArrayList<JMenuItem>(25);
    //...
    JMenuItem item1 = ...
    menuList.add(item);
    JMenuItem item2 = ...
    menuList.add(item);
    
    //...
    
    public void actionPerformed(ActionEvent e) {
        JMenuItem item = (JMenuItem)e.getSource();
        int index = menuList.indexOf(item);
    

    You Could...

    Make use of the Action API

    public class IndexedAction extends AbstractAction {
        private int index;
        public IndexedAction(int index, String name) {
            this.index = index;
            putValue(NAME, name);
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            // Use the index some how...
        }
    }
    
    //...
    
    JPopupMenu menu = new JPopupMenu();
    menu.add(new IndexedAction(0, "Item 1"));
    menu.add(new IndexedAction(1, "Item 2"));
    menu.addSeparator();
    menu.add(new IndexedAction(2, "Item 3"));
    menu.add(new IndexedAction(3, "Item 4"));
    

    You Could...

    Set the actionCommand property of the items...

    JPopupMenu pm = ...;
    pm.add("Item 1").setActionCommand("0");
    pm.add("Item 2").setActionCommand("1");
    menu.addSeparator();
    pm.add("Item 3").setActionCommand("2");
    pm.add("Item 4").setActionCommand("3");
    

    The problem with this is you're going to have to parse the actionCommand of the ActionEvent back to an int...not a really sound proof solution...

    You Could...

    Set the clientProperty of each JMenuItem

    JPopupMenu pm = ...;
    pm.add("Item 1").putClientProperty("keyValue", 0);
    pm.add("Item 2").putClientProperty("keyValue", 1);
    menu.addSeparator();
    pm.add("Item 3").putClientProperty("keyValue", 2);
    pm.add("Item 4").putClientProperty("keyValue", 3);
    

    But this gets messy...

    public void actionPerformed(ActionEvent e) {
        JMenuItem item = (JMenuItem)e.getSource();
        Object value = item.getClientProperty("keyValue");
        if (value instanceof Integer) {
            int index = ((Integer)value).intValue();
    

    There's probably other solutions, but without knowing why you want to do this, it makes it impossible to make an accurate suggestion...sorry