有没有一种方法可以检测JPopupMenu中的当前选择(SelectionModel ChangeListener不起作用)

时间:2019-10-16 12:30:35

标签: java swing jpopupmenu

我想检测JPopupMenu内的选择何时更改。不是在单击菜单项时,而是在选择菜单项(布防)时。用简单的话来说,我想检测一下:

preview

应该起作用的是在其ChangeListener上添加一个SelectionModel,但它似乎没有响应选择事件:

public class PopupSelection extends JFrame {
    private static final long serialVersionUID = 363879723515243543L;

    public PopupSelection() {
        super("something");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        JLabel label = new JLabel("right click me");

        JPopupMenu menu = new JPopupMenu();
        menu.getSelectionModel().addChangeListener(System.out::println);

        JMenuItem menuItem1 = new JMenuItem("Item1");
        JMenuItem menuItem2 = new JMenuItem("Item2");
        JMenuItem menuItem3 = new JMenuItem("Item3");
        menu.add(menuItem1);
        menu.add(menuItem2);
        menu.add(menuItem3);

        label.setComponentPopupMenu(menu);

        getContentPane().add(label);
        setSize(400, 400);
        setLocationRelativeTo(null);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new PopupSelection().setVisible(true));
    }
}

我尝试过的第二件事是使用PropertyChangeListener,但它也不起作用(也未检测到此特定事件):

menu.addPropertyChangeListener(System.out::println);

我知道有一种替代方法是向每个ChangeListener添加一个JMenuItem,并且每次迭代JPopupMenu的所有组件以查找被选中的那个,但这不是我想遵循的解决方案,因为它将在我的代码中增加不必要的复杂性。

那么,有没有办法检测选择?

在使用XY problem的情况下,我的最终目标是当用户使用箭头按钮更改菜单的选择时正确地增加/减少this scrollbar

2 个答案:

答案 0 :(得分:1)

在项目的按钮模型上使用更改侦听器。解决方法如下:

import java.awt.Component;
import java.awt.FlowLayout;
import java.util.stream.Stream;

import javax.swing.AbstractButton;
import javax.swing.ButtonModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * <code>PopupSelection</code>.
 */
public class PopupSelection extends JFrame {
    private static final long serialVersionUID = 363879723515243543L;

    public PopupSelection() {
        super("something");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        JLabel label = new JLabel("right click me");

        JPopupMenu menu = new MyPopupMenu();
        menu.getSelectionModel().addChangeListener(System.out::println);

        JMenuItem menuItem1 = new JMenuItem("Item1");
        JMenuItem menuItem2 = new JMenuItem("Item2");
        JMenuItem menuItem3 = new JMenuItem("Item3");
        menu.add(menuItem1);
        menu.add(menuItem2);
        menu.add(menuItem3);

        label.setComponentPopupMenu(menu);

        getContentPane().add(label);
        setSize(400, 400);
        setLocationRelativeTo(null);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new PopupSelection().setVisible(true));
    }

    private static class MyPopupMenu extends JPopupMenu {

        private final ChangeListener listener = this::changed;

        @Override
        protected void addImpl(Component comp, Object constraints, int index) {
            super.addImpl(comp, constraints, index);
            if (comp instanceof AbstractButton) {
                ((AbstractButton) comp).getModel().addChangeListener(listener);
            }
        }

        @Override
        public void remove(int index) {
            Component comp = getComponent(index);
            if (comp instanceof AbstractButton) {
                ((AbstractButton) comp).getModel().removeChangeListener(listener);
            }
            super.remove(index);
        }

        private void changed(ChangeEvent e) {
            ButtonModel model = (ButtonModel) e.getSource();
            AbstractButton selected = Stream.of(getComponents()).filter(AbstractButton.class::isInstance)
                    .map(AbstractButton.class::cast)
                    .filter(b -> b.getModel().isArmed() && b.getModel() == model).findAny().orElse(null);
            setSelected(selected);
        }
    }
}

答案 1 :(得分:1)

您不必向每个ChangeListener添加JMenuItem,而是可以向MenuSelectionManager添加ChangeListener

MenuSelectionManager.defaultManager().addChangeListener(e -> {
  Object o = e.getSource();
  if (o instanceof MenuSelectionManager) {
    MenuSelectionManager m = (MenuSelectionManager) o;
    printMenuElementArray(m.getSelectedPath());
  }
});

PopupSelection2.java

import java.awt.*;
import javax.swing.*;

public class PopupSelection2 extends JFrame {
  public PopupSelection2() {
    super("something");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setLayout(new FlowLayout());

    JLabel label = new JLabel("right click me");

    JPopupMenu menu = new JPopupMenu();
    menu.getSelectionModel().addChangeListener(System.out::println);

    JMenuItem menuItem1 = new JMenuItem("Item1");
    JMenuItem menuItem2 = new JMenuItem("Item2");
    JMenuItem menuItem3 = new JMenuItem("Item3");
    menu.add(menuItem1);
    menu.add(menuItem2);
    menu.add(menuItem3);

    label.setComponentPopupMenu(menu);

    MenuSelectionManager.defaultManager().addChangeListener(e -> {
      Object o = e.getSource();
      if (o instanceof MenuSelectionManager) {
        MenuSelectionManager m = (MenuSelectionManager) o;
        printMenuElementArray(m.getSelectedPath());
      }
    });

    getContentPane().add(label);
    setSize(400, 400);
    setLocationRelativeTo(null);
  }

  // @see javax/swing/MenuSelectionManager.java
  private static void printMenuElementArray(MenuElement[] path) {
    System.out.println("Path is(");
    for (int i = 0, j = path.length; i < j ; i++) {
      for (int k = 0; k <= i; k++) {
        System.out.print("  ");
      }
      MenuElement me = path[i];
      if (me instanceof JMenuItem) {
        System.out.println(((JMenuItem)me).getText() + ", ");
      } else if (me instanceof JMenuBar) {
        System.out.println("JMenuBar, ");
      } else if (me instanceof JPopupMenu) {
        System.out.println("JPopupMenu, ");
      } else if (me == null) {
        System.out.println("NULL , ");
      } else {
        System.out.println("" + me + ", ");
      }
    }
    System.out.println(")");
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> new PopupSelection2().setVisible(true));
  }
}