如果您想继续使用setComponentPopupMenu(这很好,因为它以跨平台方式处理弹出窗口的鼠标和键盘调用),您可以覆盖JPopupMenu.show(Component, int, int) 以选择适当的行。
JPopupMenu jPopupMenu = new JPopupMenu() {
@Override
public void show(Component invoker, int x, int y) {
int row = jList.locationToIndex(new Point(x, y));
if (row != -1) {
jList.setSelectedIndex(row);
}
super.show(invoker, x, y);
}
};
jList.setComponentPopupMenu(jPopupMenu);
请注意,当您的弹出窗口通过键盘调用时(并且您也没有覆盖目标组件上的getPopupLocation),您在JPopupMenu.show 中获得的x、y 位置将是您的组件的中点。如果在这种情况下已经有选择,您可能不想更改选择。
我想出的解决键盘与鼠标调用问题的解决方案是在组件上设置一个客户端属性,覆盖getPopupLocation,然后在显示弹出窗口时检查它。当通过键盘调用时,getPopupLocation 的参数将是 null。这是核心代码(可能在组件及其弹出菜单可用的实用程序类中实现)。
private static final String POPUP_TRIGGERED_BY_MOUSE_EVENT = "popupTriggeredByMouseEvent"; // NOI18N
public static Point getPopupLocation(JComponent invoker, MouseEvent event)
{
boolean popupTriggeredByMouseEvent = event != null;
invoker.putClientProperty(POPUP_TRIGGERED_BY_MOUSE_EVENT, Boolean.valueOf(popupTriggeredByMouseEvent));
if (popupTriggeredByMouseEvent)
{
return event.getPoint();
}
return invoker.getMousePosition();
}
public static boolean isPopupTriggeredByMouseEvent(JComponent invoker)
{
return Boolean.TRUE.equals(invoker.getClientProperty(POPUP_TRIGGERED_BY_MOUSE_EVENT));
}
然后在你的组件中覆盖getPopupLocation:
@Override
public Point getPopupLocation(MouseEvent event)
{
return PopupMenuUtils.getPopupLocation(this, event);
}
并调用isPopupTriggeredByMouseEvent 覆盖JPopupMenu.show 以确定是否选择弹出位置处的行(或任何可能对底层组件有意义的操作):
JPopupMenu jPopupMenu = new JPopupMenu() {
@Override
public void show(Component invoker, int x, int y) {
int row = jList.locationToIndex(new Point(x, y));
if (row != -1 && PopupMenuUtils.isPopupTriggeredByMouseEvent((JComponent) invoker)) {
jList.setSelectedIndex(row);
}
super.show(invoker, x, y);
}
};