繁体   English   中英

如何在Swing中的两个按钮中添加“默认按钮”功能?

[英]How can I add “Default Button” functionality to two buttons in Swing?

在每个窗口/面板中,我都将Enter键映射为defaultButton(这意味着按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);
}

现在,我需要的基本上是相同的代码,但是通过使用Escape更改Enter或向...添加侦听器。...我不确定。

编辑:我必须在Java 1.4中做到这一点,我知道如果我立即说出它会很棒。

(SwingX项目的)JXRootPane默认具有它,您可以执行以下操作

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

或另一种非常简单的方法

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

我设法通过在打开的面板中添加按键侦听器来解决此问题,如下所示

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

这样做:

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键还是单击此键都将执行相同的操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM