您可以通过 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 的父组件不能为空。
当然,仅仅实例化一个 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");
}
}
}
}
}
“就数学定律而言,就现实而言,它们是不确定的,就它们而言,它们是确定的,它们并不与现实有关。”
艾尔伯特爱因斯坦