Java всплывающее меню и jlist - PullRequest
21 голосов
/ 15 мая 2011

вот моя проблема: у меня есть 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 ]

27 голосов
/ 15 мая 2011

Не делай 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
    }
}

Это должно работать.

РЕДАКТИРОВАТЬ: Код теперь проверяет события press и release, потому что некоторые платформы показывают всплывающие окна при нажатии мыши, а другие при отпускании. См. учебник по Swing для получения дополнительной информации.

9 голосов
/ 19 декабря 2013

Если вы хотите продолжать использовать 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 на целевом компоненте), местоположение x, y, которое вы получите в JPopupMenu.show, будет средней точкой вашего компонента. Если в этом случае уже есть выбор, вы, вероятно, не хотите менять его.

Решение, которое я нашел для решения проблемы вызова клавиатуры и мыши, состояло в том, чтобы установить свойство клиента для компонента с переопределением 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);
    }
};
...