Как добавить функциональность «Кнопка по умолчанию» к двум кнопкам в Swing? - PullRequest
2 голосов
/ 15 сентября 2011

В каждом окне / панели клавиша Enter отображается как кнопка по умолчанию (это означает, что нажатие клавиши Enter вызывает нажатие кнопки, даже если нажатая кнопка не находится в фокусе).Мне нужно сопоставить клавишу Escape с другой кнопкой, которая также вызывает вторую кнопку независимо от фокуса.Код для клавиши ввода:

// We get the button
IButton iButton = (IButton)actionToolbar.getComponent(actionToolbar.getComponentCount() - 1);
// We get the window
Window window = SwingUtilities.getWindowAncestor(this);
// Only these two types of windows should have this behaviour
if (window instanceof JFrame) {
    ((JFrame)window).getRootPane().setDefaultButton(iButton);
}
else if (window instanceof JDialog) {
    ((JDialog)window).getRootPane().setDefaultButton(iButton);
}

Теперь мне нужен в основном тот же код, но с изменением Enter с помощью Escape или добавлением прослушивателя .... чего-то, я не уверен, что.

РЕДАКТИРОВАТЬ: Я должен сделать это в Java 1.4, что я знаю, было бы здорово, если бы я сказал это немедленно.

Ответы [ 4 ]

4 голосов
/ 15 сентября 2011

JXRootPane (из проекта SwingX) имеет его по умолчанию, вы можете сделать что-то вроде

private void installKeyboardActions() {
    Action escAction = new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent evt) {
            JButton cancelButton = getCancelButton();
            if (cancelButton != null) {
                cancelButton.doClick(20);
            }
        }

        /**
         * Overridden to hack around #566-swing: 
         * JXRootPane eats escape keystrokes from datepicker popup.
         * Disable action if there is no cancel button.<p>
         * 
         * That's basically what RootPaneUI does - only not in 
         * the parameterless isEnabled, but in the one that passes
         * in the sender (available in UIAction only). We can't test 
         * nor compare against core behaviour, UIAction has
         * sun package scope. <p>
         * 
         * Cont'd (Issue #1358-swingx: popup menus not closed)
         * The extended hack is inspired by Rob Camick's
         * <a href="http://tips4java.wordpress.com/2010/10/17/escape-key-and-dialog/"> Blog </a>
         * and consists in checking if the the rootpane has a popup's actionMap "inserted". 
         * NOTE: this does not work if the popup or any of its children is focusOwner.
         */
        @Override
        public boolean isEnabled() {
            Component component = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
            if (component instanceof JComponent) {
                Action cancelPopup = ((JComponent)component).getActionMap().get("cancel");
                if (cancelPopup != null) return false;
            }
            return (cancelButton != null) && (cancelButton.isEnabled());
        }
    };
    getActionMap().put("esc-action", escAction);
    InputMap im = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
    KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
    im.put(key, "esc-action");
}


/**
 * Sets the <code>cancelButton</code> property,
 * which determines the current default cancel button for this <code>JRootPane</code>.
 * The cancel button is the button which will be activated 
 * when a UI-defined activation event (typically the <b>ESC</b> key) 
 * occurs in the root pane regardless of whether or not the button 
 * has keyboard focus (unless there is another component within 
 * the root pane which consumes the activation event,
 * such as a <code>JTextPane</code>).
 * For default activation to work, the button must be an enabled
 * descendant of the root pane when activation occurs.
 * To remove a cancel button from this root pane, set this
 * property to <code>null</code>.
 *
 * @param cancelButton the <code>JButton</code> which is to be the cancel button
 * @see #getCancelButton() 
 *
 * @beaninfo
 *  description: The button activated by default for cancel actions in this root pane
 */
public void setCancelButton(JButton cancelButton) { 
    JButton old = this.cancelButton;

    if (old != cancelButton) {
        this.cancelButton = cancelButton;

        if (old != null) {
            old.repaint();
        }
        if (cancelButton != null) {
            cancelButton.repaint();
        } 
    }

    firePropertyChange("cancelButton", old, cancelButton);        
}

/**
 * Returns the value of the <code>cancelButton</code> property. 
 * @return the <code>JButton</code> which is currently the default cancel button
 * @see #setCancelButton
 */
public JButton getCancelButton() { 
    return cancelButton;
}
1 голос
/ 28 сентября 2011

Мне удалось решить эту проблему, добавив ключевой слушатель к открытой панели, как это

InputMap iMap = theTaskWindow.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
     iMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escape");
     ActionMap aMap = theTaskWindow.getRootPane().getActionMap();
     aMap.put("escape", new AbstractAction() {
      private static final long serialVersionUID = 1L;
      public void actionPerformed(ActionEvent e){
        doCancel();
      }
     });
1 голос
/ 15 сентября 2011

или другой и очень простой способ

import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;

public class ExampleKeyStrokes {

    private JFrame frame = new JFrame();
    private JButton button;

    public ExampleKeyStrokes() {
        button = new JButton(new AbstractAction(" push ENTER ") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        button.setText(" Please push ENTER ");
        //button.setPreferredSize(new Dimension(200, 50));
        frame.add(button);
        frame.getRootPane().setDefaultButton(button);
        frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("F2"), "clickButton");
        frame.getRootPane().getActionMap().put("clickButton", new AbstractAction() {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                button.doClick();
            }
        });
        frame.setLocation(150, 150);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        setFocusButton();
    }

    private void setFocusButton() {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                button.grabFocus();
                button.requestFocus();
                button.requestFocusInWindow();
            }
        });
    }

    static public void main(String[] s) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                ExampleKeyStrokes eKS = new ExampleKeyStrokes();
            }
        });
    }
}
0 голосов
/ 15 сентября 2011

Это делает это:

window.getContentPane().registerKeyboardAction(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            onCancel();
        }
    }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

Ваш второй JButton должен также вызывать onCancel () при нажатии.Так что либо нажатие клавиши «escape», либо нажатие на нее оба сделают одно и то же.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...