Как включить ESC-Close для JPopupMenu, если основное окно закрывается на ESC? - PullRequest
2 голосов
/ 28 сентября 2010

Представьте себе две общие ситуации: JDialog (или JFrame), который закрывается на VK_ESCAPE (устанавливается как привязка ключа на корневой панели) и внутреннее JPopupMenu, которое также должно закрываться на ESC. Проблема в том, что нажатие escape всегда закрывает диалоговое окно - событие, если всплывающее окно видно. Очевидно, что всплывающее окно даже не получает ключевое событие, поэтому оно не может быть использовано всплывающим окном. Есть ли способ заставить это работать правильно, чтобы на первом ESC-событии всплывающее окно закрывалось, а на втором диалоговое окно закрывалось? Кстати: он работает с JComboBox, который по умолчанию закрывается при нажатии escape.

1 Ответ

4 голосов
/ 29 сентября 2010

Найти общее решение было непросто. Нам нужно учитывать, когда:

  1. используется легковесное всплывающее окно
  2. используется всплывающее окно с большим весом

Я определил, что в обоих случаях корневая панель действительно имеет фокус при нажатии клавиши выхода.

В первом случае я просто ищу корневую панель, чтобы увидеть, было ли JPopupMenu добавлено в GUI. Если это так, то мы можем просто закрыть всплывающее окно.

Во втором случае создается окно, содержащее JPopupMenu, поэтому я выполняю поиск, чтобы увидеть, отображается ли видимое настраиваемое всплывающее окно. Если так, то я избавляюсь от окна.

Если ни один из двух приведенных выше случаев не верен, вы можете просто закрыть диалоговое окно.

import java.awt.*;
import java.awt.event.*;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;

public class DialogEscape extends JDialog
{
    private JPopupMenu popup;

    public DialogEscape()
    {
        popup = new JPopupMenu();
        popup.add( new JMenuItem("SubMenuA") );
        popup.add( new JMenuItem("SubMenuB") );
        popup.add( new JMenuItem("SubMenuC") );
        popup.add( new JMenuItem("SubMenuD") );

        String[] items = { "Select Item", "Color", "Shape", "Fruit" };
        JComboBox comboBox = new JComboBox( items );
        add(comboBox, BorderLayout.NORTH);

        JTextField textField = new JTextField("Right Click For Popup");
        textField.setComponentPopupMenu(popup);
        add(textField);

        KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
        Action escapeAction = new AbstractAction()
        {
            public void actionPerformed(ActionEvent e)
            {
                boolean openPopup = false;
                Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();

                //  Check if light weight popup is being used

                List<JPopupMenu> popups = SwingUtils.getDescendantsOfType(JPopupMenu.class, (Container)c, true);

                for (JPopupMenu p: popups)
                {
                    p.setVisible( false );
                    openPopup = true;
                }

                //  Check if a heavy weight popup is being used

                Window window = SwingUtilities.windowForComponent(c);
                Window[] windows = window.getOwnedWindows();

                for (Window w: windows)
                {
                    if (w.isVisible()
                    &&  w.getClass().getName().endsWith("HeavyWeightWindow"))
                    {
                        openPopup = true;
                        w.dispose();
                    }
                }

                //  No popups so close the Window

                if (! openPopup)
//                  SwingUtilities.windowForComponent(c).setVisible(false);
                    SwingUtilities.windowForComponent(c).dispose();
            }
        };

        getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escapeKeyStroke, "ESCAPE");
        getRootPane().getActionMap().put("ESCAPE", escapeAction);
    }

    public static void main(String[] args)
    {
        String laf = null;
        laf = "javax.swing.plaf.metal.MetalLookAndFeel";
//      laf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
//      laf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";

        try { UIManager.setLookAndFeel(laf); }
        catch (Exception e2) { System.out.println(e2); }

        JDialog dialog = new DialogEscape();
        dialog.setDefaultCloseOperation( HIDE_ON_CLOSE );
        dialog.setSize(200, 200);
        dialog.setLocationRelativeTo(null);
        dialog.setVisible( true );
    }
}

Вам также потребуется загрузить класс Swing Utils .

...