将 JFrame 的默认关闭操作保留为 JFrame.DO_NOTHING_ON_CLOSE,但使用 WindowListener(或更简洁地说,WindowAdapter)监听关闭尝试。
您可以对菜单项和按钮使用相同的 AbstractAction,然后在 WindowListener 中调用该操作的方法。例如
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.*;
public class ClosingJFrame {
public static void main(String[] args) {
final JFrame frame = new JFrame("My Frame");
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
final CloseAction closeAction = new CloseAction(frame);
JPanel panel = new JPanel();
panel.add(new JButton(closeAction));
JMenuItem exitMenuItem = new JMenuItem(closeAction);
JMenu menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_F);
menu.add(exitMenuItem);
JMenuBar menuBar = new JMenuBar();
menuBar.add(menu);
frame.setJMenuBar(menuBar);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
closeAction.confirmClosing();
}
});
frame.add(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
class CloseAction extends AbstractAction {
private JFrame mainFrame;
public CloseAction(JFrame mainFrame) {
super("Exit");
putValue(MNEMONIC_KEY, KeyEvent.VK_X);
this.mainFrame = mainFrame;
}
@Override
public void actionPerformed(ActionEvent e) {
confirmClosing();
}
public void confirmClosing() {
int confirmed = JOptionPane.showConfirmDialog(mainFrame,
"Are you sure you want to quit?", "Confirm quit",
JOptionPane.YES_NO_OPTION);
if (confirmed == JOptionPane.YES_OPTION) {
// clean up code
System.exit(0);
}
}
}
编辑
糟糕,我忘记了你的 ctrl-Q 按键位。为此使用相同的操作,并使用 KeyBindings 将其绑定到 ctrl-q 键。改进后的代码:
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.*;
public class ClosingJFrame {
public static void main(String[] args) {
final JFrame frame = new JFrame("My Frame");
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
final CloseAction closeAction = new CloseAction(frame);
JPanel panel = new JPanel();
panel.add(new JButton(closeAction));
JMenuItem exitMenuItem = new JMenuItem(closeAction);
JMenu menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_F);
menu.add(exitMenuItem);
JMenuBar menuBar = new JMenuBar();
menuBar.add(menu);
frame.setJMenuBar(menuBar);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
closeAction.confirmClosing();
}
});
// also use the same Action in your ctrl-q key bindings
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = panel.getInputMap(condition);
ActionMap actionMap = panel.getActionMap();
KeyStroke ctrlQKey = KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.CTRL_DOWN_MASK);
inputMap.put(ctrlQKey, ctrlQKey.toString());
actionMap.put(ctrlQKey.toString(), closeAction);
frame.add(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
class CloseAction extends AbstractAction {
private JFrame mainFrame;
public CloseAction(JFrame mainFrame) {
super("Exit");
putValue(MNEMONIC_KEY, KeyEvent.VK_X);
this.mainFrame = mainFrame;
}
@Override
public void actionPerformed(ActionEvent e) {
confirmClosing();
}
public void confirmClosing() {
int confirmed = JOptionPane.showConfirmDialog(mainFrame,
"Are you sure you want to quit?", "Confirm quit",
JOptionPane.YES_NO_OPTION);
if (confirmed == JOptionPane.YES_OPTION) {
// clean up code
System.exit(0);
}
}
}
编辑 2
这句话让我很担心:
然后继续处理所有帧
因为这意味着您有多个 JFrame。如果是这样,您应该阅读此链接,因为它会解释为什么通常不需要这样做:The Use of Multiple JFrames, Good/Bad Practice?
编辑 3
根据 Rob Camick 的评论:
您也可以通过执行以下操作为 CloseAction 设置加速器:
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("control Q"));
然后菜单项将为您完成键绑定。
这将进入 CloseAction 的构造函数,如下所示:
public CloseAction(JFrame mainFrame) {
super("Exit");
putValue(MNEMONIC_KEY, KeyEvent.VK_X);
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("control Q"));
this.mainFrame = mainFrame;
}