有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

是否可以为JOptionPane对话框中的按钮分配热键和助记符?我希望能够在JOptionPane生成的消息对话框中,选择Yes、No和Cancel,按Y键点击Yes按钮,按N键点击No按钮,按escape键激活escape按钮。类似地,在带有“确定”和“取消”按钮的对话框中,我希望能够使用enter和escape来激活它们

我已经尝试将JButtons传递到JOptionPane的按钮对象数组中,并且已经设置了助记符。助记符工作,按钮在对话框中正确显示,但是,当它们被激活时,它们不能正常工作。最明显的是,它们没有处理对话框

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


共 (4) 个答案

  1. # 1 楼答案

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

        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);
    
  2. # 2 楼答案

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

    JOptionPane p = new JOptionPane();
    Component[] c = p.getComponents();
    
  3. # 3 楼答案

    按如下方式使用UIManager:

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

    您可以通过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");
                    }
                }
            }
        }
    }
    

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

    爱因斯坦