JOptionPane showMessageDialog - 取消焦点 'OK' 按钮

JOptionPane showMessageDialog - Un-focus 'OK' button

我正在尝试创建只有一个按钮(即确定)的 showMessageDialog。我希望那个按钮没有焦点。这意味着当对话框打开时,用户单击 Enter 键,对话框不应关闭。使用时必须单击 'OK' 按钮,然后只有对话框会消失。

但我现在得到的是 'OK' 按钮始终处于焦点状态。所以当对话框弹出时,用户没有看到并按下 Enter 键,对话框关闭。

为什么我需要这个:这不是错误消息。用户在继续之前必须看到的唯一信息性消息。在这种情况下,大显示器离用户位置有点远。我已经编写了在对话框出现时发出声音的代码,但用户可能听不到并按下 Enter 键。所以我希望用户看到对话框并单击“确定”按钮

示例代码:

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;


import java.awt.Color;
import java.awt.Font;

public class MessageDialogInFrame extends JFrame{

    public MessageDialogInFrame() {
        getContentPane().setBackground(Color.DARK_GRAY);
        setTitle("Message Dialog in Frame");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        setResizable(false);
        setSize(400, 300);
        getContentPane().setLayout(null);
    }

    public static void main(String[] args){
        ImageIcon icon = new ImageIcon("src/images/turtle64.png");
        JTextArea commentTextArea = new JTextArea("Hello", 10, 50);
        commentTextArea.setBackground(Color.YELLOW);
        Font font = new java.awt.Font("Dialog", 0, 15);
        commentTextArea.setFont(font);
        commentTextArea.setEditable(false);
        JScrollPane scrollPane = new JScrollPane(commentTextArea);
        scrollPane.setBackground(Color.YELLOW);       

        JOptionPane.showMessageDialog(new MessageDialogInFrame(), 
                "I appear as part of the frame!!", "Customized Dialog", 
                JOptionPane.INFORMATION_MESSAGE, icon);
    }
}

原码:

private static int showColoredDialog(int category, Component parentComp, String message, String title, int optionType, int messageType, Color color) {
    JTextArea commentTextArea = new JTextArea(message, 10, 50);
    commentTextArea.setBackground(color);
    commentTextArea.setFont(UiFactory.getInfo().getLabelFont());
    commentTextArea.setEditable(false);
    JScrollPane scrollPane = new JScrollPane(commentTextArea);
    scrollPane.setBackground(color);

    switch (category) {
    case 0:
        JOptionPane.showMessageDialog(parentComp, scrollPane, title, messageType);
        return 0;
    case 1:
        return JOptionPane.showConfirmDialog(parentComp, scrollPane, title, optionType, messageType);
    }
    return -1;
}

解决方案:

int result = JOptionPane.CLOSED_OPTION;
final JOptionPane pane = new JOptionPane(scrollPane, JOptionPane.WARNING_MESSAGE, JOptionPane.OK_OPTION, null, new String[] {"OK"});
            JDialog dialog = pane.createDialog(null, title);
            commentTextArea.requestFocus();
            dialog.setVisible(true);
            if (pane.getValue() != null) result = JOptionPane.OK_OPTION;
            return result;

一种方法:通过其构造函数创建一个 JOptionPane 对象,递归地在其组件树中搜索 JButton,并将其设为 non-focusable:

JOptionPane optionPane = new JOptionPane();
optionPane.setMessage("Fubars Rule!");
optionPane.setMessageType(JOptionPane.PLAIN_MESSAGE);
optionPane.setOptionType(JOptionPane.DEFAULT_OPTION);
recursiveUnfocusButtons(optionPane);
JDialog dialog = optionPane.createDialog(null, "Option Title");
dialog.setVisible(true); 
System.exit(0);

还有魔术酱:

private static void recursiveUnfocusButtons(Component component) {
    if (component instanceof JButton) {
        component.setFocusable(false);
        return;
    } else if (component instanceof Container) {
        for (Component c : ((Container) component).getComponents()) {
            recursiveUnfocusButtons(c);
        }
    }
} 

要取消输入操作,您需要更改 JOptionPane 中输入键的键绑定:

import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.*;

public class JOptionNoFocus {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JOptionPane optionPane = new JOptionPane();
            optionPane.setMessage("Fubars Rule!");
            optionPane.setMessageType(JOptionPane.PLAIN_MESSAGE);
            optionPane.setOptionType(JOptionPane.DEFAULT_OPTION);

            KeyStroke enterStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
            optionPane.getInputMap(JComponent.WHEN_FOCUSED).put(enterStroke, enterStroke.toString());
            optionPane.getActionMap().put(enterStroke.toString(), new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    // do nothing
                }
            });

            recursiveUnfocusButtons(optionPane);
            JDialog dialog = optionPane.createDialog(null, "Option Title");
            dialog.setVisible(true); 
            System.exit(0);
        });
    }

    private static void recursiveUnfocusButtons(Component component) {
        if (component instanceof JButton) {
            JButton button = (JButton) component;
            button.setFocusable(false);
            return;
        } else if (component instanceof Container) {
            for (Component c : ((Container) component).getComponents()) {
                recursiveUnfocusButtons(c);
            }
        }
    }
}

不过,一旦您开始创建更复杂的对话框,只需跳过创建 JDialog 的步骤,而是创建您自己的 JDialog,将组件放置在您想要的位置。如果您希望它们在处理之前停止应用程序,请将它们设置为模态。