Как предотвратить скрытие меню отключенным JMenuItem при нажатии?

В моем приложении Java Swing я заметил, что когда я нажимаю на отключенный JMenuItem в JPopupMenu, он скрывает меню, но я не хочу его скрывать, как будто ничего не нажато. Есть ли способ предотвратить это ?

-----------------------------------> Обновление: добавлен пример кода:

JMenuItem saveMenuItem = new JMenuItem();

saveMenuItem.setEnabled(false);

saveMenuItem.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        saveMenuItemActionPerformed();
    }
});
add(saveMenuItem);

private void saveMenuItemActionPerformed() {
    System.out.println( "Save clicked." );
}

person Brad    schedule 06.03.2011    source источник
comment
вы можете показать код, который вы написали?   -  person harshit    schedule 07.03.2011
comment
@harshit: я приложил пример кода для инициализации JMenuItem. Я не делаю никаких действий в событии щелчка ... Это скрытие меню - это просто поведение Java по умолчанию.   -  person Brad    schedule 07.03.2011
comment
Я прикрепил пример кода... Чтобы быстрее получить помощь, опубликуйте SSCCE (pscode.org/sscce.html), а не фрагменты кода.   -  person Andrew Thompson    schedule 14.03.2011
comment
@Andrew: Спасибо, Эндрю. Я сделаю это в следующий раз.   -  person Brad    schedule 14.03.2011


Ответы (7)


Это проверено и работает.

Look & Feel решает, как обрабатывать события мыши в отключенных пунктах меню. В любом случае, вы можете перехватывать нежелательные события с помощью пользовательского файла MenuItem. Просто используйте этот код (скопируйте/вставьте):

public class CustomMenuItem extends JMenuItem {

    public CustomMenuItem(String text) {
        super(text);
    }

    public CustomMenuItem() {
        super();
    }

    protected void processMouseEvent(MouseEvent e) {
        if (isEnabled()) super.processMouseEvent(e);
    }
}

Во-первых, адаптируйте код в соответствии с вашими потребностями (необязательно).
Наконец, замените любые JMenuItem на CustomMenuItem.

Вот и все!

person Alba Mendez    schedule 17.04.2011
comment
@jmendeth ... Есть ли подобное решение для отключенных элементов JComboBox? - person Brad; 20.04.2011
comment
@Brad да, просто создайте свой собственный класс JComboBox и скопируйте в него метод processMouseEvent. Затем замените любой JComboBox своим классом. Если хотите, могу выложить пример. - person Alba Mendez; 21.04.2011
comment
@jmendeth ... Я этого не понимаю ... Разве processMouseEvent не должен применяться к элементам JComboBox, а не к самому JcomboBox? ... Буду признателен, если вы напишете мне пример. - person Brad; 22.04.2011
comment
@Брэд извини, я не правильно выразился. Да, processMouseEvent необходимо применять ко всем элементам во всплывающем окне. В этом случае элементы ComboBox. - person Alba Mendez; 22.04.2011
comment
@jmendeth ... Эмммм, в любом случае спасибо. - person Brad; 22.04.2011

не уверен, как предотвратить. но вы можете установитьVisible(false), чтобы предотвратить его отображение. Кроме того, если пользователь щелкнет меню отключения, никаких действий не произойдет.

person harshit    schedule 07.03.2011
comment
Извините, я не понимаю, что вы подразумеваете под setVisible(false)? - person Brad; 07.03.2011
comment
вы можете сделать saveMenuItem.setVisible(false) - person harshit; 10.03.2011
comment
Но я хочу сделать его видимым и отключенным! Если я щелкнул отключенный элемент, никаких действий не произойдет, но меню закроется. Попытайся. - person Brad; 13.03.2011

Когда вы отключаете JMenuItem, вы должны удалить ActionListener, связанный с этим JMenuItem, с помощью метода jMenuItem.removeActionListener(). Если вы удалите это, это действие не вызовет слушателя, и всплывающее окно не исчезнет. Я надеюсь, что это поможет достичь вашей цели.

person Burhan Valikarimwala    schedule 08.03.2011

Вы попробовали этот метод: http://download.oracle.com/javase/6/docs/api/javax/swing/JMenuItem.html#setArmed%28boolean%29

«включить пункт меню, чтобы его можно было выбрать», что, я думаю, поможет, если установлено значение false.

person jm2    schedule 10.03.2011

Короче говоря, вы можете это сделать, но вам придется написать свой собственный прослушиватель мыши, что может потребовать много копий и вставок из исходного кода jdk, что не очень хорошая идея, и я не уверен, какие лицензионные ограничения он будет помещен в ваш код.

Я бы начал копать с этого метода:

javax.swing.plaf.basic.BasicMenuItemUI.Handler#mouseReleased

который, кажется, является точкой входа, из которой механизм обработки меню скрывает всплывающее окно. я бы посмотрел повнимательнее

javax.swing.plaf.basic.BasicPopupMenuUI.MouseGrabber#stateChanged

EDIT Разрабатывая ответ @Burhan Valikarimwala, попробуйте этот подход: удалите все прослушиватели действий из отключенного JMenuItem и сохраните их в некоторой статической временной структуре (скажем, Map<WeakReference<JMenuItem>, List<MouseListener>>), таким образом, он не будет скрывать всплывающее окно . Когда вы снова сделаете пункт меню включенным, добавьте всех слушателей обратно. Превратите его в какой-нибудь полезный метод, и он будет бесшовным.

person Denis Tulskiy    schedule 08.03.2011

Единственное решение, которое я мог придумать, для вашей проблемы с отключением JMenuItem, вызывающим его скрытие, приведено ниже:


import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;

public class PopupMenuDisableNoCloseTest extends JPanel implements ActionListener
{
    public static void main(String[] args)
    {
        PopupMenuDisableNoCloseTest p = new PopupMenuDisableNoCloseTest();
        p.setPreferredSize(new Dimension(200, 300));
        p.setBackground(Color.GREEN);
        JPanel contentPane = new JPanel();
        contentPane.add(p);
        final JFrame f = new JFrame();
        final JPopupMenu popup = new JPopupMenu();
        final JMenuItem menuItem1 = new JMenuItem("A popup menu item");
        menuItem1.addActionListener(p);
        menuItem1.addMouseListener(new MouseAdapter()
        {
            @Override
            public void mousePressed(MouseEvent e)
            {
                System.out.println(" menuItem1 mousePressed e.getPoint()=" + e.getPoint());
            }

            @Override
            public void mouseReleased(MouseEvent e)
            {
                System.out.println(" menuItem1 mouseReleased e.getPoint()=" + e.getPoint());
                if(!menuItem1.isEnabled())
                    popup.setVisible(true);
            }
        });
        menuItem1.setEnabled(false);
        popup.add(menuItem1);
        JMenuItem menuItem2 = new JMenuItem("Another popup menu item");
        menuItem2.addActionListener(p);
        popup.add(menuItem2);
        MouseListener popupListener = new PopupListener(popup);
        f.addMouseListener(popupListener);
        f.setContentPane(contentPane);
        f.setSize(800, 600);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        JMenuItem source = (JMenuItem) (e.getSource());
        String s = "Action event detected. Event source: " + source.getText();
        System.out.println("s=" + s);
    }

    static class PopupListener extends MouseAdapter
    {
        JPopupMenu popup;
        PopupListener(JPopupMenu popupMenu)
        {
            popup = popupMenu;
        }

        @Override
        public void mousePressed(MouseEvent e)
        {
            maybeShowPopup(e);
        }

        @Override
        public void mouseReleased(MouseEvent e)
        {
            maybeShowPopup(e);
        }

        private void maybeShowPopup(MouseEvent e)
        {
            if(e.isPopupTrigger())
            {
                popup.show(e.getComponent(),
                        e.getX(), e.getY());
            }
        }
    }
}

В основном скрытие происходит, когда ваш релиз находится внутри границ JMenuItem, поэтому мы проверяем, отключен ли он, а затем снова показываем всплывающее окно. Так как к этому времени уже решено, что он будет скрыт. Я пытался вызвать super.mouseRelease с другим MouseEvent, указывающим на внешний компонент и использующим предыдущий, но это ничего не помогает.

В любом случае это решение работает. Наслаждайся, Боро

person Boro    schedule 05.04.2011

Я думаю, что в Java7 это было исправлено.

person Andras    schedule 28.11.2013