我想检测JPopupMenu
内的选择何时更改。不是在单击菜单项时,而是在选择菜单项(布防)时。用简单的话来说,我想检测一下:
应该起作用的是在其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:↑ ↓
答案 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));
}
}