Java Swing弹出式菜单和JList

21

这是我的问题: 我有一个JList和一个弹出菜单。当我右键单击JList时,弹出菜单会显示。问题在于,鼠标指向的JList项不会被选中。 而我希望它能够这样做。当我把光标放在列表中的某个项目上并按下右键时,我希望发生两件事情。选择我点击的项目并显示弹出菜单。

我尝试过这个:

jLists.addMouseListener(new MouseAdapter() {

     @Override
     public void mousePressed(MouseEvent e) {
            jList.setSelectedIndex(jList.locationToIndex(e.getPoint()));
     }
});

jList.setComponentPopupMenu(jPopupMenu);

但它只显示弹出菜单。 如果我删除这一行:

jList.setComponentPopupMenu(jPopupMenu);

那么,右键选择功能可以使用(但弹出菜单不显示)。

所以,你认为最好的方法是让这两个功能都起作用吗?

谢谢,对我的英语表示抱歉。

2个回答

28

不要使用setComponentPopupMenu。在MouseAdapter中执行以下操作:

public void mousePressed(MouseEvent e)  {check(e);}
public void mouseReleased(MouseEvent e) {check(e);}

public void check(MouseEvent e) {
    if (e.isPopupTrigger()) { //if the event shows the menu
        jList.setSelectedIndex(jList.locationToIndex(e.getPoint())); //select the item
        jPopupMenu.show(jList, e.getX(), e.getY()); //and show the menu
    }
}

这应该可以工作。

编辑:代码现在检查pressrelease事件,因为一些平台在鼠标按下时显示弹出窗口,而另一些在释放时显示。有关更多信息,请参见 Swing教程


2
说实话,我会选择使用 if(e.getButton() == MouseEvent.BUTTON3) 而不是 if(e.isPopupTrigger()),原因非常简单,触发方法对我总是返回 false。否则我的代码将完全与 @jmendeth +1 相同。 - Boro
好的,现在没问题了。我忘记删除 table.setComponentPopupMenu(popup);,因此在释放时没有触发。所以在 Wins 上你也需要释放。知道这点很好 :) - Boro
3
иҜ·жіЁж„ҸпјҢйҖҡиҝҮиҝҷз§Қж–№ејҸйҒҝе…ҚдҪҝз”ЁsetComponentPopupMenuж„Ҹе‘ізқҖжӮЁе°Ҷж— жі•йҖҡиҝҮй”®зӣҳи°ғз”Ёеј№еҮәиҸңеҚ•гҖӮ - Rangi Keen
@RangiKeen 很好的观点。也许可以通过重写 JPopupMenu 更加清晰地完成。 - Alba Mendez
@RangiKeen 哦天啊,我才意识到你的回答是关于这个的!点赞。 - Alba Mendez
显示剩余4条评论

10

如果您想继续使用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);
}

重写JPopupMenu.show方法并调用isPopupTriggeredByMouseEvent来确定是否选择弹出位置上的行(或对于基础组件可能有意义的任何动作):

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);
    }
};

1
缺失的部分是 jList=new JList<ContactItem>() { @Override public Point getPopupLocation(MouseEvent event) { return JListUtility.getPopupLocation(this, event); } }; - palindrom
谢谢,@palindrom。我更新了我的答案并包括了getPopupLocation的使用。 - Rangi Keen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接