设置 JOptionPane 对话框的助记符和热键

发布于 2024-08-06 13:55:55 字数 329 浏览 4 评论 0原文

是否可以为 JOptionPane 对话框中的按钮分配热键和助记符?我希望能够在 JOptionPane 生成的带有“是”、“否”和“取消”选项的消息对话框中,按 Y 键单击“是”按钮,按 N 键单击“否”按钮,然后按 escape 键激活转义按钮。同样,在带有“确定”和“取消”按钮的对话框中,我希望能够通过输入和转义来激活它们。

我已尝试将 JButtons 传递到 JOptionPane 的按钮对象数组中,并已设置助记符。助记符有效并且按钮在对话框中正确显示,但是,它们在激活时无法正常工作。最值得注意的是,他们不会处理对话框。

将热键和助记符添加到 JOptionPane 对话框按钮的正确方法是什么?

Is it possible to assign hotkeys and mnemonics to the buttons in a JOptionPane Dialog? I'd like to be able, in a JOptionPane generated message dialog with the options Yes, No and Cancel, press Y to hit the Yes button, N to hit the No button and escape to activate the escape button. Similarly in a dialog with Okay and Cancel buttons I'd like to be able to activate them with enter and escape.

I've attempted passing JButtons into the JOptionPane's button Object array with the Mnemonics set already. The mnemonics work and the buttons show up correctly in the dialogs, however, they do not act properly when they are activated. Most noticeably they do not dispose of the dialog.

What is the correct way to add hotkeys and Mnemonics to a JOptionPane Dialog's buttons?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

仙女山的月亮 2024-08-13 13:55:55

您可以创建 JOptionPane,然后循环遍历窗格的组件(子项等),检查是否有任何组件是 instanceof JButton,如果是,请检查文本,并设置正确的助记词。

JOptionPane p = new JOptionPane();
Component[] c = p.getComponents();

You can create your JOptionPane, and then loop through the components of the pane (children etc.) checking to see if any components are instanceof JButton, and if so check the text, and set the proper mnemonic.

JOptionPane p = new JOptionPane();
Component[] c = p.getComponents();
梦一生花开无言 2024-08-13 13:55:55

使用 UIManager 如下:

UIManager.put("OptionPane.okButtonMnemonic", "79");  // for Setting 'O' as mnemonic
UIManager.put("OptionPane.cancelButtonMnemonic", "67"); // for Setting 'C' as mnemonic

Make use of UIManager as follows:

UIManager.put("OptionPane.okButtonMnemonic", "79");  // for Setting 'O' as mnemonic
UIManager.put("OptionPane.cancelButtonMnemonic", "67"); // for Setting 'C' as mnemonic
回首观望 2024-08-13 13:55:55

您可以通过 Swing Worker 寻找在父窗口中打开的新窗口。然后检查它是否是一个JDialog并提取按钮区域。然后将按键分配给按钮。这适用于 JOptionPane 的静态方法。

这是 Swing Worker 类 - 只需实例化它并在调用之前执行它以显示 JOptionPane:

import java.awt.Component;
import java.awt.Window;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import javax.swing.FocusManager;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class HotKeyWorker extends SwingWorker<JComponent, Integer>
{
    private static final long TIMEOUT = 30000; //Don't wait forever for the JOptionPane
    private final String buttonAreaName;
    private final Map<String, ButtonData> buttonDataMap;
    private final Window owner;
    
    public HotKeyWorker(Component owner, Map<String, ButtonData> buttonDataMap)
    {
        this.buttonDataMap = buttonDataMap;
        if(owner instanceof Window)
            this.owner = (Window)owner;
        else if(owner != null)
            this.owner = SwingUtilities.windowForComponent(owner);
        else
            this.owner = null;
        buttonAreaName = getButtonAreaName();
    }

    @Override
    public JComponent doInBackground()
    {
        if(owner == null) return null;
        if(buttonAreaName == null) return null;
        long timeout = System.currentTimeMillis() + TIMEOUT;
        Window dialog = null;
        while(dialog == null && System.currentTimeMillis() < timeout)
        {
            dialog = FocusManager.getCurrentManager().getFocusedWindow();
            if(dialog != null)
                if(dialog.getOwner() != owner) 
                    dialog = null;
        }
        if(dialog instanceof JDialog)
            return getButtonArea(((JDialog)dialog).getRootPane());
        return null;
    }

    @Override
    public void done()
    {
        try
        {
            JComponent buttonArea = get();
            if(buttonArea != null)
                for(Component c : buttonArea.getComponents())
                    if(c instanceof JButton)
                        setHotKey((JButton)c);

        }
        catch(InterruptedException | ExecutionException ex) { /* Failed */ } 
    }

    private JComponent getButtonArea(JComponent component)
    {
        JComponent result = null;
        if(component.getName() != null)
            if(component.getName().equals(buttonAreaName) && component.getParent() instanceof JOptionPane)
                return component;
        for(Component c : component.getComponents())
            if(c instanceof JComponent)
                if((result = getButtonArea((JComponent)c)) != null)
                    return result;
        return result;
    }

    private void setHotKey(JButton button)
    {
        if(button.getText().isEmpty()) return;
        ButtonData data = buttonDataMap.get(button.getText());
        if(data == null) return;
        button.setText(data.updatedButtonText);
        button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(data.hotKeyCode, 0), data.actionKey);
        button.getActionMap().put(data.actionKey, new ButtonPress(button));
    }
    
    private String getButtonAreaName()
    {
        JButton trace = new JButton();
        Object[] options = { trace };
        JOptionPane temp = new JOptionPane();
        temp.setOptions(options);
        Component buttonArea = trace.getParent();
        if(buttonArea != null)
            return buttonArea.getName();
        return null;
    }
}

这是两个帮助器类,可以使事情变得更清晰:

public class ButtonData
{
    public String updatedButtonText;
    public int hotKeyCode;
    public String actionKey;
    public ButtonData(String updatedButtonText, int hotKeyCode, String actionKey)
    {
        this.updatedButtonText = updatedButtonText;
        this.hotKeyCode = hotKeyCode;
        this.actionKey = actionKey;
    }
}

import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;

public class ButtonPress extends AbstractAction
{
    private final JButton button;
    public ButtonPress(JButton button) { this.button = button; }
    @Override
    public void actionPerformed(ActionEvent event) { button.doClick(); }
}

就是您将如何使用它:

ButtonData yesData = new ButtonData("<html><span style=\"color:Blue;\">Y</span>es</html>", KeyEvent.VK_Y, "yes");
ButtonData noData = new ButtonData("<html><span style=\"color:Blue;\">N</span>o</html>", KeyEvent.VK_N, "no");
ButtonData cancelData = new ButtonData("<html><span style=\"color:Blue;\">C</span>ancel</html>", KeyEvent.VK_C, "cancel");
Map<String, ButtonData> map = new HashMap<>();
map.put("Yes", yesData);
map.put("No", noData);
map.put("Cancel", cancelData);
HotKeyWorker worker = new HotKeyWorker(component, map);
worker.execute();
int result = JOptionPane.showConfirmDialog(component, "Just a text", "Confirm", JOptionPane.YES_NO_CANCEL_OPTION);

这是一个工作示例:

import javax.swing.JComponent;
import java.awt.Window;
import javax.swing.FocusManager;
import javax.swing.JDialog;
import java.awt.Component;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.JLabel;
import javax.swing.AbstractAction;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.KeyStroke;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import javax.swing.SwingWorker;

public class Test 
{
    public static void main(String[] args) 
    {
        Frame frame = new Frame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    
    private static class Frame extends JFrame
    {
        public Frame()
        {
            init();
        }

        private void init()
        {
            setSize(300,100);
            setTitle("Hot Key Test");
            add(new Panel());
        }

        private class Panel extends JPanel
        {
            private final JButton testButton;
            private final JLabel resultLabel;
            public Panel()
            {
                String testKey = "test";
                testButton = new JButton("<html><span style=\"color:Blue;\">T</span>est</html>");
                testButton.addActionListener((event) -> { test(this); });
                testButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0), testKey);
                testButton.getActionMap().put(testKey, new ButtonPress(testButton));
                resultLabel = new JLabel("No Result");
                init();
            }

            private void init()
            {
                add(testButton);
                add(resultLabel);
            }

            private void test(Component component)
            {
                String anotherTestKey = "Test";
                JButton anotherTestButton = new JButton("<html><span style=\"color:Blue;\">T</span>est</html>");
                anotherTestButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0), anotherTestKey);
                anotherTestButton.getActionMap().put(anotherTestKey, new ButtonPress(anotherTestButton));
                JLabel anotherTestLabel = new JLabel("No Result has been selected");
                JPanel testPanel = new JPanel();
                testPanel.add(anotherTestButton);
                testPanel.add(anotherTestLabel);
                anotherTestButton.addActionListener((event) -> { anotherTest(testPanel, anotherTestLabel); });


                ButtonData yesData = new ButtonData("<html><span style=\"color:Blue;\">Y</span>es</html>", KeyEvent.VK_Y, "yes");
                ButtonData noData = new ButtonData("<html><span style=\"color:Blue;\">N</span>o</html>", KeyEvent.VK_N, "no");
                ButtonData cancelData = new ButtonData("<html><span style=\"color:Blue;\">C</span>ancel</html>", KeyEvent.VK_C, "cancel");
                Map<String, ButtonData> map = new HashMap<>();
                map.put("Yes", yesData);
                map.put("No", noData);
                map.put("Cancel", cancelData);
                HotKeyWorker worker = new HotKeyWorker(component, map);
                worker.execute();
                int result = JOptionPane.showConfirmDialog(component, testPanel, "Confirm", JOptionPane.YES_NO_CANCEL_OPTION);
                switch(result)
                {
                    case 0 : resultLabel.setText("Yes Pressed"); break;
                    case 1 : resultLabel.setText("No Pressed"); break;
                    case 2 : resultLabel.setText("Cancel Pressed"); break;
                    default: resultLabel.setText("OptionPane Closed");
                }
            }

            public void anotherTest(Component component, JLabel label)
            {
                ButtonData fredData = new ButtonData("<html><span style=\"color:Blue;\">F</span>red</html>", KeyEvent.VK_F, "fred");
                ButtonData wilmaData = new ButtonData("<html><span style=\"color:Blue;\">W</span>ilma</html>", KeyEvent.VK_W, "wilma");
                ButtonData barneyData = new ButtonData("<html>B<span style=\"color:Blue;\">a</span>rney</html>", KeyEvent.VK_A, "barney");
                ButtonData bettyData = new ButtonData("<html>B<span style=\"color:Blue;\">e</span>tty</html>", KeyEvent.VK_E, "betty");
                Map<String, ButtonData> map = new HashMap<>();
                map.put("Fred", fredData);
                map.put("Wilma", wilmaData);
                map.put("Barney", barneyData);
                map.put("Betty", bettyData);
                HotKeyWorker worker = new HotKeyWorker(component, map);
                worker.execute();

                String[] options = {"Fred", "Wilma", "Barney", "Betty" };
                int result = JOptionPane.showOptionDialog(component, "Who do you like?", "Confirm", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, 0);
                switch(result)
                {
                    case 0 : label.setText("I like Fred"); break;
                    case 1 : label.setText("I like Wilma"); break;
                    case 2 : label.setText("I like Barney"); break;
                    case 3 : label.setText("I like Betty"); break;
                    default: label.setText("I decline to answer");
                }
            }
            
            private class HotKeyWorker extends SwingWorker<JComponent, Integer>
            {
                private static final long TIMEOUT = 30000; //Don't wait forever for the JOptionPane
                private final String buttonAreaName;
                private final Map<String, ButtonData> buttonDataMap;
                private final Window owner;

                public HotKeyWorker(Component owner, Map<String, ButtonData> buttonDataMap)
                {
                    this.buttonDataMap = buttonDataMap;
                    if(owner instanceof Window)
                        this.owner = (Window)owner;
                    else if(owner != null)
                        this.owner = SwingUtilities.windowForComponent(owner);
                    else
                        this.owner = null;
                    buttonAreaName = getButtonAreaName();
                }

                @Override
                public JComponent doInBackground()
                {
                    if(owner == null) return null;
                    if(buttonAreaName == null) return null;
                    long timeout = System.currentTimeMillis() + TIMEOUT;
                    Window dialog = null;
                    while(dialog == null && System.currentTimeMillis() < timeout)
                    {
                        dialog = FocusManager.getCurrentManager().getFocusedWindow();
                        if(dialog != null)
                            if(dialog.getOwner() != owner) 
                                dialog = null;
                    }
                    if(dialog instanceof JDialog)
                        return getButtonArea(((JDialog)dialog).getRootPane());
                    return null;
                }

                @Override
                public void done()
                {
                    try
                    {
                        JComponent buttonArea = get();
                        if(buttonArea != null)
                            for(Component c : buttonArea.getComponents())
                                if(c instanceof JButton)
                                    setHotKey((JButton)c);

                    }
                    catch(InterruptedException | ExecutionException ex) { /* Failed */ } 
                }

                private JComponent getButtonArea(JComponent component)
                {
                    JComponent result = null;
                    if(component.getName() != null)
                        if(component.getName().equals(buttonAreaName) && component.getParent() instanceof JOptionPane)
                            return component;
                    for(Component c : component.getComponents())
                        if(c instanceof JComponent)
                            if((result = getButtonArea((JComponent)c)) != null)
                                return result;
                    return result;
                }

                private void setHotKey(JButton button)
                {
                    if(button.getText().isEmpty()) return;
                    ButtonData data = buttonDataMap.get(button.getText());
                    if(data == null) return;
                    button.setText(data.updatedButtonText);
                    button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(data.hotKeyCode, 0), data.actionKey);
                    button.getActionMap().put(data.actionKey, new ButtonPress(button));
                }

                private String getButtonAreaName()
                {
                    JButton trace = new JButton();
                    Object[] options = { trace };
                    JOptionPane temp = new JOptionPane();
                    temp.setOptions(options);
                    Component buttonArea = trace.getParent();
                    if(buttonArea != null)
                        return buttonArea.getName();
                    return null;
                }
            }
            
            private class ButtonData
            {
                public String updatedButtonText;
                public int hotKeyCode;
                public String actionKey;
                public ButtonData(String updatedButtonText, int hotKeyCode, String actionKey)
                {
                    this.updatedButtonText = updatedButtonText;
                    this.hotKeyCode = hotKeyCode;
                    this.actionKey = actionKey;
                }
            }
            
            private class ButtonPress extends AbstractAction
            {
                private final JButton button;
                public ButtonPress(JButton button) { this.button = button; }
                @Override
                public void actionPerformed(ActionEvent event) { button.doClick(); }
            }
        }
    }
}

这适用于所有 JOptionPane 静态方法。只要您不是在父组件的窗口中随机弹出窗口,这就可以正常工作。注意:JOptionPane 的父组件不能为 null。


当然,实例化 JOptionPane 并自定义它可能更容易。以下是执行此操作的类:

import java.awt.Component;
import javax.swing.Icon;
import javax.swing.JOptionPane;
import javax.swing.JDialog;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.AbstractAction;
import javax.swing.Action;
import java.awt.event.ActionEvent;

public class HotKeyOptionPane
{
    public static int showOptionDialog(Component parentComponent,
                                    Object message, String title,
                                    int optionType, int messageType,
                                    Icon icon, HotKey[] options,
                                    Object initialValue)
    {
        JButton[] buttons = new JButton[options.length];
        for(int i = 0; i < options.length; i++)
            buttons[i] = new JButton(options[i].text);
        JOptionPane pane = new JOptionPane(message, messageType, optionType, icon, buttons, initialValue);
        for(int option = 0; option < buttons.length; option++)
            setButtonAction(buttons[option], options[option].keyCode, option, pane);
        JDialog dialog = pane.createDialog(parentComponent, title);
        dialog.setVisible(true);
 
        if (pane.getValue() instanceof Integer)
            return (Integer)pane.getValue();
        return -1;   
    }
    
    private static void setButtonAction(JButton button, int hotKey, Integer option, JOptionPane pane)
    {
        Action action = new AbstractAction()
        {
            @Override
            public void actionPerformed(ActionEvent event)
            {
                pane.setValue(option);
                pane.firePropertyChange(JOptionPane.VALUE_PROPERTY, JOptionPane.DEFAULT_OPTION, option);    
            }
        };
        button.addActionListener(action);
        button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(hotKey, 0), button.getText());
        button.getActionMap().put(button.getText(), action);
    }      
}

并且

public class HotKey 
{
    public String text;
    public int keyCode;
    public HotKey(String text, int keyCode)
    {
        this.text = text;
        this.keyCode = keyCode;
    }
}

这就是您将如何使用它们:

import javax.swing.JComponent;
import java.awt.Component;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import javax.swing.JLabel;
import java.awt.event.KeyEvent;
import javax.swing.KeyStroke;

public class Test 
{
    public static void main(String[] args) 
    {
        Frame frame = new Frame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    
    private static class Frame extends JFrame
    {
        public Frame()
        {
            init();
        }

        private void init()
        {
            setSize(300,100);
            setTitle("Hot Key Test");
            add(new Panel());
        }

        private class Panel extends JPanel
        {
            private final JButton testButton;
            private final JLabel resultLabel;
            public Panel()
            {
                String testKey = "test";
                testButton = new JButton("<html><span style=\"color:Blue;\">T</span>est</html>");
                testButton.addActionListener((event) -> { test(this); });
                testButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0), testKey);
                testButton.getActionMap().put(testKey, new ButtonPress(testButton));
                resultLabel = new JLabel("No Result");
                init();
            }

            private void init()
            {
                add(testButton);
                add(resultLabel);
            }
            
            private void test(Component component)
            {
                HotKey yesOption = new HotKey("<html><span style=\"color:Blue;\">Y</span>es</html>", KeyEvent.VK_Y);
                HotKey noOption = new HotKey("<html><span style=\"color:Blue;\">N</span>o</html>", KeyEvent.VK_N);
                HotKey cancelOption = new HotKey("<html><span style=\"color:Blue;\">C</span>ancel</html>", KeyEvent.VK_C);
                HotKey[] options = { yesOption, noOption, cancelOption };
                int result = HotKeyOptionPane.showOptionDialog(component, "Just a test", "Testing", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, 0);
                switch(result)
                {
                    case 0 : resultLabel.setText("Yes Pressed"); break;
                    case 1 : resultLabel.setText("No Pressed"); break;
                    case 2 : resultLabel.setText("Cancel Pressed"); break;
                    default: resultLabel.setText("OptionPane Closed");
                }
            }
        }
    }
}

“就数学定律而言,它们涉及现实,它们是不确定的,而就数学定律而言,它们是确定的,它们并不涉及现实。 ”

阿尔伯特·爱因斯坦

You can look for a new window opening in the parent window by means of a Swing Worker. Then check if it is a JDialog and extract the button area. Then assign keys to the buttons. This works for the static methods of JOptionPane.

This is the Swing Worker class - just instantiate it and execute it right before the call to show the JOptionPane:

import java.awt.Component;
import java.awt.Window;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import javax.swing.FocusManager;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class HotKeyWorker extends SwingWorker<JComponent, Integer>
{
    private static final long TIMEOUT = 30000; //Don't wait forever for the JOptionPane
    private final String buttonAreaName;
    private final Map<String, ButtonData> buttonDataMap;
    private final Window owner;
    
    public HotKeyWorker(Component owner, Map<String, ButtonData> buttonDataMap)
    {
        this.buttonDataMap = buttonDataMap;
        if(owner instanceof Window)
            this.owner = (Window)owner;
        else if(owner != null)
            this.owner = SwingUtilities.windowForComponent(owner);
        else
            this.owner = null;
        buttonAreaName = getButtonAreaName();
    }

    @Override
    public JComponent doInBackground()
    {
        if(owner == null) return null;
        if(buttonAreaName == null) return null;
        long timeout = System.currentTimeMillis() + TIMEOUT;
        Window dialog = null;
        while(dialog == null && System.currentTimeMillis() < timeout)
        {
            dialog = FocusManager.getCurrentManager().getFocusedWindow();
            if(dialog != null)
                if(dialog.getOwner() != owner) 
                    dialog = null;
        }
        if(dialog instanceof JDialog)
            return getButtonArea(((JDialog)dialog).getRootPane());
        return null;
    }

    @Override
    public void done()
    {
        try
        {
            JComponent buttonArea = get();
            if(buttonArea != null)
                for(Component c : buttonArea.getComponents())
                    if(c instanceof JButton)
                        setHotKey((JButton)c);

        }
        catch(InterruptedException | ExecutionException ex) { /* Failed */ } 
    }

    private JComponent getButtonArea(JComponent component)
    {
        JComponent result = null;
        if(component.getName() != null)
            if(component.getName().equals(buttonAreaName) && component.getParent() instanceof JOptionPane)
                return component;
        for(Component c : component.getComponents())
            if(c instanceof JComponent)
                if((result = getButtonArea((JComponent)c)) != null)
                    return result;
        return result;
    }

    private void setHotKey(JButton button)
    {
        if(button.getText().isEmpty()) return;
        ButtonData data = buttonDataMap.get(button.getText());
        if(data == null) return;
        button.setText(data.updatedButtonText);
        button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(data.hotKeyCode, 0), data.actionKey);
        button.getActionMap().put(data.actionKey, new ButtonPress(button));
    }
    
    private String getButtonAreaName()
    {
        JButton trace = new JButton();
        Object[] options = { trace };
        JOptionPane temp = new JOptionPane();
        temp.setOptions(options);
        Component buttonArea = trace.getParent();
        if(buttonArea != null)
            return buttonArea.getName();
        return null;
    }
}

These are the two helper classes to make things a little cleaner:

public class ButtonData
{
    public String updatedButtonText;
    public int hotKeyCode;
    public String actionKey;
    public ButtonData(String updatedButtonText, int hotKeyCode, String actionKey)
    {
        this.updatedButtonText = updatedButtonText;
        this.hotKeyCode = hotKeyCode;
        this.actionKey = actionKey;
    }
}

and

import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;

public class ButtonPress extends AbstractAction
{
    private final JButton button;
    public ButtonPress(JButton button) { this.button = button; }
    @Override
    public void actionPerformed(ActionEvent event) { button.doClick(); }
}

This is how you would use it:

ButtonData yesData = new ButtonData("<html><span style=\"color:Blue;\">Y</span>es</html>", KeyEvent.VK_Y, "yes");
ButtonData noData = new ButtonData("<html><span style=\"color:Blue;\">N</span>o</html>", KeyEvent.VK_N, "no");
ButtonData cancelData = new ButtonData("<html><span style=\"color:Blue;\">C</span>ancel</html>", KeyEvent.VK_C, "cancel");
Map<String, ButtonData> map = new HashMap<>();
map.put("Yes", yesData);
map.put("No", noData);
map.put("Cancel", cancelData);
HotKeyWorker worker = new HotKeyWorker(component, map);
worker.execute();
int result = JOptionPane.showConfirmDialog(component, "Just a text", "Confirm", JOptionPane.YES_NO_CANCEL_OPTION);

Here is a working example:

import javax.swing.JComponent;
import java.awt.Window;
import javax.swing.FocusManager;
import javax.swing.JDialog;
import java.awt.Component;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.JLabel;
import javax.swing.AbstractAction;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.KeyStroke;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import javax.swing.SwingWorker;

public class Test 
{
    public static void main(String[] args) 
    {
        Frame frame = new Frame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    
    private static class Frame extends JFrame
    {
        public Frame()
        {
            init();
        }

        private void init()
        {
            setSize(300,100);
            setTitle("Hot Key Test");
            add(new Panel());
        }

        private class Panel extends JPanel
        {
            private final JButton testButton;
            private final JLabel resultLabel;
            public Panel()
            {
                String testKey = "test";
                testButton = new JButton("<html><span style=\"color:Blue;\">T</span>est</html>");
                testButton.addActionListener((event) -> { test(this); });
                testButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0), testKey);
                testButton.getActionMap().put(testKey, new ButtonPress(testButton));
                resultLabel = new JLabel("No Result");
                init();
            }

            private void init()
            {
                add(testButton);
                add(resultLabel);
            }

            private void test(Component component)
            {
                String anotherTestKey = "Test";
                JButton anotherTestButton = new JButton("<html><span style=\"color:Blue;\">T</span>est</html>");
                anotherTestButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0), anotherTestKey);
                anotherTestButton.getActionMap().put(anotherTestKey, new ButtonPress(anotherTestButton));
                JLabel anotherTestLabel = new JLabel("No Result has been selected");
                JPanel testPanel = new JPanel();
                testPanel.add(anotherTestButton);
                testPanel.add(anotherTestLabel);
                anotherTestButton.addActionListener((event) -> { anotherTest(testPanel, anotherTestLabel); });


                ButtonData yesData = new ButtonData("<html><span style=\"color:Blue;\">Y</span>es</html>", KeyEvent.VK_Y, "yes");
                ButtonData noData = new ButtonData("<html><span style=\"color:Blue;\">N</span>o</html>", KeyEvent.VK_N, "no");
                ButtonData cancelData = new ButtonData("<html><span style=\"color:Blue;\">C</span>ancel</html>", KeyEvent.VK_C, "cancel");
                Map<String, ButtonData> map = new HashMap<>();
                map.put("Yes", yesData);
                map.put("No", noData);
                map.put("Cancel", cancelData);
                HotKeyWorker worker = new HotKeyWorker(component, map);
                worker.execute();
                int result = JOptionPane.showConfirmDialog(component, testPanel, "Confirm", JOptionPane.YES_NO_CANCEL_OPTION);
                switch(result)
                {
                    case 0 : resultLabel.setText("Yes Pressed"); break;
                    case 1 : resultLabel.setText("No Pressed"); break;
                    case 2 : resultLabel.setText("Cancel Pressed"); break;
                    default: resultLabel.setText("OptionPane Closed");
                }
            }

            public void anotherTest(Component component, JLabel label)
            {
                ButtonData fredData = new ButtonData("<html><span style=\"color:Blue;\">F</span>red</html>", KeyEvent.VK_F, "fred");
                ButtonData wilmaData = new ButtonData("<html><span style=\"color:Blue;\">W</span>ilma</html>", KeyEvent.VK_W, "wilma");
                ButtonData barneyData = new ButtonData("<html>B<span style=\"color:Blue;\">a</span>rney</html>", KeyEvent.VK_A, "barney");
                ButtonData bettyData = new ButtonData("<html>B<span style=\"color:Blue;\">e</span>tty</html>", KeyEvent.VK_E, "betty");
                Map<String, ButtonData> map = new HashMap<>();
                map.put("Fred", fredData);
                map.put("Wilma", wilmaData);
                map.put("Barney", barneyData);
                map.put("Betty", bettyData);
                HotKeyWorker worker = new HotKeyWorker(component, map);
                worker.execute();

                String[] options = {"Fred", "Wilma", "Barney", "Betty" };
                int result = JOptionPane.showOptionDialog(component, "Who do you like?", "Confirm", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, 0);
                switch(result)
                {
                    case 0 : label.setText("I like Fred"); break;
                    case 1 : label.setText("I like Wilma"); break;
                    case 2 : label.setText("I like Barney"); break;
                    case 3 : label.setText("I like Betty"); break;
                    default: label.setText("I decline to answer");
                }
            }
            
            private class HotKeyWorker extends SwingWorker<JComponent, Integer>
            {
                private static final long TIMEOUT = 30000; //Don't wait forever for the JOptionPane
                private final String buttonAreaName;
                private final Map<String, ButtonData> buttonDataMap;
                private final Window owner;

                public HotKeyWorker(Component owner, Map<String, ButtonData> buttonDataMap)
                {
                    this.buttonDataMap = buttonDataMap;
                    if(owner instanceof Window)
                        this.owner = (Window)owner;
                    else if(owner != null)
                        this.owner = SwingUtilities.windowForComponent(owner);
                    else
                        this.owner = null;
                    buttonAreaName = getButtonAreaName();
                }

                @Override
                public JComponent doInBackground()
                {
                    if(owner == null) return null;
                    if(buttonAreaName == null) return null;
                    long timeout = System.currentTimeMillis() + TIMEOUT;
                    Window dialog = null;
                    while(dialog == null && System.currentTimeMillis() < timeout)
                    {
                        dialog = FocusManager.getCurrentManager().getFocusedWindow();
                        if(dialog != null)
                            if(dialog.getOwner() != owner) 
                                dialog = null;
                    }
                    if(dialog instanceof JDialog)
                        return getButtonArea(((JDialog)dialog).getRootPane());
                    return null;
                }

                @Override
                public void done()
                {
                    try
                    {
                        JComponent buttonArea = get();
                        if(buttonArea != null)
                            for(Component c : buttonArea.getComponents())
                                if(c instanceof JButton)
                                    setHotKey((JButton)c);

                    }
                    catch(InterruptedException | ExecutionException ex) { /* Failed */ } 
                }

                private JComponent getButtonArea(JComponent component)
                {
                    JComponent result = null;
                    if(component.getName() != null)
                        if(component.getName().equals(buttonAreaName) && component.getParent() instanceof JOptionPane)
                            return component;
                    for(Component c : component.getComponents())
                        if(c instanceof JComponent)
                            if((result = getButtonArea((JComponent)c)) != null)
                                return result;
                    return result;
                }

                private void setHotKey(JButton button)
                {
                    if(button.getText().isEmpty()) return;
                    ButtonData data = buttonDataMap.get(button.getText());
                    if(data == null) return;
                    button.setText(data.updatedButtonText);
                    button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(data.hotKeyCode, 0), data.actionKey);
                    button.getActionMap().put(data.actionKey, new ButtonPress(button));
                }

                private String getButtonAreaName()
                {
                    JButton trace = new JButton();
                    Object[] options = { trace };
                    JOptionPane temp = new JOptionPane();
                    temp.setOptions(options);
                    Component buttonArea = trace.getParent();
                    if(buttonArea != null)
                        return buttonArea.getName();
                    return null;
                }
            }
            
            private class ButtonData
            {
                public String updatedButtonText;
                public int hotKeyCode;
                public String actionKey;
                public ButtonData(String updatedButtonText, int hotKeyCode, String actionKey)
                {
                    this.updatedButtonText = updatedButtonText;
                    this.hotKeyCode = hotKeyCode;
                    this.actionKey = actionKey;
                }
            }
            
            private class ButtonPress extends AbstractAction
            {
                private final JButton button;
                public ButtonPress(JButton button) { this.button = button; }
                @Override
                public void actionPerformed(ActionEvent event) { button.doClick(); }
            }
        }
    }
}

This will work for all JOptionPane static methods. This will work fine as long as your not randomly popping up windows in the parent component's window. Note: the parent component of the JOptionPane cannot be null.


Of course, it is probably easier just to instantiate a JOptionPane and customize it. Here are the classes to do that:

import java.awt.Component;
import javax.swing.Icon;
import javax.swing.JOptionPane;
import javax.swing.JDialog;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.AbstractAction;
import javax.swing.Action;
import java.awt.event.ActionEvent;

public class HotKeyOptionPane
{
    public static int showOptionDialog(Component parentComponent,
                                    Object message, String title,
                                    int optionType, int messageType,
                                    Icon icon, HotKey[] options,
                                    Object initialValue)
    {
        JButton[] buttons = new JButton[options.length];
        for(int i = 0; i < options.length; i++)
            buttons[i] = new JButton(options[i].text);
        JOptionPane pane = new JOptionPane(message, messageType, optionType, icon, buttons, initialValue);
        for(int option = 0; option < buttons.length; option++)
            setButtonAction(buttons[option], options[option].keyCode, option, pane);
        JDialog dialog = pane.createDialog(parentComponent, title);
        dialog.setVisible(true);
 
        if (pane.getValue() instanceof Integer)
            return (Integer)pane.getValue();
        return -1;   
    }
    
    private static void setButtonAction(JButton button, int hotKey, Integer option, JOptionPane pane)
    {
        Action action = new AbstractAction()
        {
            @Override
            public void actionPerformed(ActionEvent event)
            {
                pane.setValue(option);
                pane.firePropertyChange(JOptionPane.VALUE_PROPERTY, JOptionPane.DEFAULT_OPTION, option);    
            }
        };
        button.addActionListener(action);
        button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(hotKey, 0), button.getText());
        button.getActionMap().put(button.getText(), action);
    }      
}

and

public class HotKey 
{
    public String text;
    public int keyCode;
    public HotKey(String text, int keyCode)
    {
        this.text = text;
        this.keyCode = keyCode;
    }
}

And this is how you would use them:

import javax.swing.JComponent;
import java.awt.Component;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import javax.swing.JLabel;
import java.awt.event.KeyEvent;
import javax.swing.KeyStroke;

public class Test 
{
    public static void main(String[] args) 
    {
        Frame frame = new Frame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    
    private static class Frame extends JFrame
    {
        public Frame()
        {
            init();
        }

        private void init()
        {
            setSize(300,100);
            setTitle("Hot Key Test");
            add(new Panel());
        }

        private class Panel extends JPanel
        {
            private final JButton testButton;
            private final JLabel resultLabel;
            public Panel()
            {
                String testKey = "test";
                testButton = new JButton("<html><span style=\"color:Blue;\">T</span>est</html>");
                testButton.addActionListener((event) -> { test(this); });
                testButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0), testKey);
                testButton.getActionMap().put(testKey, new ButtonPress(testButton));
                resultLabel = new JLabel("No Result");
                init();
            }

            private void init()
            {
                add(testButton);
                add(resultLabel);
            }
            
            private void test(Component component)
            {
                HotKey yesOption = new HotKey("<html><span style=\"color:Blue;\">Y</span>es</html>", KeyEvent.VK_Y);
                HotKey noOption = new HotKey("<html><span style=\"color:Blue;\">N</span>o</html>", KeyEvent.VK_N);
                HotKey cancelOption = new HotKey("<html><span style=\"color:Blue;\">C</span>ancel</html>", KeyEvent.VK_C);
                HotKey[] options = { yesOption, noOption, cancelOption };
                int result = HotKeyOptionPane.showOptionDialog(component, "Just a test", "Testing", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, 0);
                switch(result)
                {
                    case 0 : resultLabel.setText("Yes Pressed"); break;
                    case 1 : resultLabel.setText("No Pressed"); break;
                    case 2 : resultLabel.setText("Cancel Pressed"); break;
                    default: resultLabel.setText("OptionPane Closed");
                }
            }
        }
    }
}

"As far as the laws of mathematics refer to reality, they are not certain, and as far as they are certain, they do not refer to reality."

Albert Einstein

清风无影 2024-08-13 13:55:55

将按钮作为参数而不是字符串发送

    JButton button1 = new JButton( "<html>" + nextQuestion1 + "</html>");
    button1.setMnemonic('a');
    JButton button2 = new JButton(nextQuestion2 + "VUHU");
    JButton button3 = new JButton(abort);
    Object[] possibleValues = new Object[]{button1,button2,button3};
    int selectedValue = showOptionDialog(owner, question, possibleValues);

Send the buttons in as parameters instead of Strings

    JButton button1 = new JButton( "<html>" + nextQuestion1 + "</html>");
    button1.setMnemonic('a');
    JButton button2 = new JButton(nextQuestion2 + "VUHU");
    JButton button3 = new JButton(abort);
    Object[] possibleValues = new Object[]{button1,button2,button3};
    int selectedValue = showOptionDialog(owner, question, possibleValues);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文