如何通过关闭JFrame直接关闭JOptionPane?
How to close JOptionPane directly by closing JFrame?
初学javax.swing
,有疑问。
我有一个 JFrame
,其 defaultCloseOperation
设置为 EXIT_ON_CLOSE
。我有另一个组件 - JOptionPane
- over JFrame
。我想要发生的是,即使焦点在 JOptionPane
消息对话框上,我也希望程序在单击 x
按钮时终止JFrame
window。
所以,准确地说,我希望在不关闭 JOptionPane
消息对话框的情况下使 JFrame
成为焦点,以便我可以关闭 JFrame
window 并因此使程序终止。
这是我的代码:
import javax.swing.*;
public class JJSS {
public JFrame jf;
public JJSS(){
jf = new JFrame();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(400, 400);
jf.setVisible(true);
}
public void runMethod(){
String str = JOptionPane.showInputDialog(jf, "Enter something...");
str = String.valueOf(new StringBuffer(str).reverse());
JOptionPane.showMessageDialog(jf, "Reversed: "+str, "Output", JOptionPane.PLAIN_MESSAGE);
}
public static void main(String[] args){
new JJSS().runMethod();
System.exit(0);
}
}
使用当前代码,当我点击 JFrame
window 的关闭按钮 (x
) 时没有任何反应。
如何在 JOptionPane 对话框仍在其上时将焦点放在 JFrame window 上,并通过关闭 JFrame window 终止程序?
对话模式是关键
您不能使用普通的 JOptionPane 或任何模态对话框执行此操作,因为模态会阻止用户在显示对话框时与 GUI 的其他组件进行交互。如果你创建一个非模式对话框,你只能让它工作,这意味着 JOptionPane 必须不是使用 JOptionPane 静态工厂方法创建,而是以非传统的方式,使用 JOptionPane 构造函数 - 检查 JOptionPane API 了解如何做到这一点。
例如:
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class NonModalJOptionPane {
private static void createAndShowGui() {
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(400, 300));
final JFrame frame = new JFrame("NonModalJOptionPane");
panel.add(new JButton(new AbstractAction("Push Me") {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane optionPane = new JOptionPane("My Message", JOptionPane.PLAIN_MESSAGE);
JDialog dialog = optionPane.createDialog(frame, "My Option");
dialog.setModalityType(ModalityType.MODELESS); // **** key ***
dialog.setVisible(true);
}
}));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
这段代码的关键在这里:
// create the JOptionPane using one of its constructors
JOptionPane optionPane = new JOptionPane("My Message", JOptionPane.PLAIN_MESSAGE);
// create a JDialog from it, tying it to the parent JFrame, here called "frame"
JDialog dialog = optionPane.createDialog(frame, "My Option");
// setting the modality type so that it is **not** modal
dialog.setModalityType(ModalityType.MODELESS); // **** key ***
// and then displaying it
dialog.setVisible(true);
在我通过其构造函数而不是通过静态方法创建 JOptionPane 的地方,我创建了一个 JDialog 并将其设置为 MODELESS , 然后显示出来。
另一个可行的选择是创建您自己的 JDialog,确保您也将其设置为非模态。
例如,您可以将以下代码添加到上面的代码中:
panel.add(new JButton(new AbstractAction("Push Me 2 -- Using Dialog") {
@Override
public void actionPerformed(ActionEvent e) {
// button that when pressed, closes the JDialog that holds it
// similar to a JOptionPane's OK button
JButton disposeWinBtn = new JButton(new DisposeWindowAction("OK", KeyEvent.VK_O));
// create a bunch of JPanels, add components to them, ...
JPanel bottomPanel = new JPanel();
bottomPanel.add(disposeWinBtn);
JLabel msgLabel = new JLabel("My Message");
JPanel msgPanel = new JPanel();
msgPanel.add(msgLabel);
JPanel panel = new JPanel(new BorderLayout());
panel.add(msgPanel, BorderLayout.CENTER);
panel.add(bottomPanel, BorderLayout.PAGE_END);
// create a JDialog whose parent component is the main JFrame
// and make sure that it is *****non-modal ***** <===== this is KEY *****
JDialog dialog = new JDialog(frame, "Dialog", ModalityType.MODELESS);
dialog.add(panel); // add the JPanel, panel, created above, with components
dialog.pack(); // have layout managers do their thing
dialog.setLocationRelativeTo(frame); // center it over the main JFrame
dialog.setVisible(true); // and display it
}
}));
就在添加第一个按钮的位置下方。您还需要 DisposeWindowAction class,它允许按钮关闭并处理显示它的 window(这里是 JDialog window):
import java.awt.Component;
import java.awt.Window;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.SwingUtilities;
@SuppressWarnings("serial")
public class DisposeWindowAction extends AbstractAction {
public DisposeWindowAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(ActionEvent e) {
Component component = (Component) e.getSource();
if (component == null) {
return;
}
Window win = SwingUtilities.getWindowAncestor(component);
if (win == null) {
return;
}
win.dispose();
}
}
初学javax.swing
,有疑问。
我有一个 JFrame
,其 defaultCloseOperation
设置为 EXIT_ON_CLOSE
。我有另一个组件 - JOptionPane
- over JFrame
。我想要发生的是,即使焦点在 JOptionPane
消息对话框上,我也希望程序在单击 x
按钮时终止JFrame
window。
所以,准确地说,我希望在不关闭 JOptionPane
消息对话框的情况下使 JFrame
成为焦点,以便我可以关闭 JFrame
window 并因此使程序终止。
这是我的代码:
import javax.swing.*;
public class JJSS {
public JFrame jf;
public JJSS(){
jf = new JFrame();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(400, 400);
jf.setVisible(true);
}
public void runMethod(){
String str = JOptionPane.showInputDialog(jf, "Enter something...");
str = String.valueOf(new StringBuffer(str).reverse());
JOptionPane.showMessageDialog(jf, "Reversed: "+str, "Output", JOptionPane.PLAIN_MESSAGE);
}
public static void main(String[] args){
new JJSS().runMethod();
System.exit(0);
}
}
使用当前代码,当我点击 JFrame
window 的关闭按钮 (x
) 时没有任何反应。
如何在 JOptionPane 对话框仍在其上时将焦点放在 JFrame window 上,并通过关闭 JFrame window 终止程序?
对话模式是关键
您不能使用普通的 JOptionPane 或任何模态对话框执行此操作,因为模态会阻止用户在显示对话框时与 GUI 的其他组件进行交互。如果你创建一个非模式对话框,你只能让它工作,这意味着 JOptionPane 必须不是使用 JOptionPane 静态工厂方法创建,而是以非传统的方式,使用 JOptionPane 构造函数 - 检查 JOptionPane API 了解如何做到这一点。
例如:
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class NonModalJOptionPane {
private static void createAndShowGui() {
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(400, 300));
final JFrame frame = new JFrame("NonModalJOptionPane");
panel.add(new JButton(new AbstractAction("Push Me") {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane optionPane = new JOptionPane("My Message", JOptionPane.PLAIN_MESSAGE);
JDialog dialog = optionPane.createDialog(frame, "My Option");
dialog.setModalityType(ModalityType.MODELESS); // **** key ***
dialog.setVisible(true);
}
}));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
这段代码的关键在这里:
// create the JOptionPane using one of its constructors
JOptionPane optionPane = new JOptionPane("My Message", JOptionPane.PLAIN_MESSAGE);
// create a JDialog from it, tying it to the parent JFrame, here called "frame"
JDialog dialog = optionPane.createDialog(frame, "My Option");
// setting the modality type so that it is **not** modal
dialog.setModalityType(ModalityType.MODELESS); // **** key ***
// and then displaying it
dialog.setVisible(true);
在我通过其构造函数而不是通过静态方法创建 JOptionPane 的地方,我创建了一个 JDialog 并将其设置为 MODELESS , 然后显示出来。
另一个可行的选择是创建您自己的 JDialog,确保您也将其设置为非模态。
例如,您可以将以下代码添加到上面的代码中:
panel.add(new JButton(new AbstractAction("Push Me 2 -- Using Dialog") {
@Override
public void actionPerformed(ActionEvent e) {
// button that when pressed, closes the JDialog that holds it
// similar to a JOptionPane's OK button
JButton disposeWinBtn = new JButton(new DisposeWindowAction("OK", KeyEvent.VK_O));
// create a bunch of JPanels, add components to them, ...
JPanel bottomPanel = new JPanel();
bottomPanel.add(disposeWinBtn);
JLabel msgLabel = new JLabel("My Message");
JPanel msgPanel = new JPanel();
msgPanel.add(msgLabel);
JPanel panel = new JPanel(new BorderLayout());
panel.add(msgPanel, BorderLayout.CENTER);
panel.add(bottomPanel, BorderLayout.PAGE_END);
// create a JDialog whose parent component is the main JFrame
// and make sure that it is *****non-modal ***** <===== this is KEY *****
JDialog dialog = new JDialog(frame, "Dialog", ModalityType.MODELESS);
dialog.add(panel); // add the JPanel, panel, created above, with components
dialog.pack(); // have layout managers do their thing
dialog.setLocationRelativeTo(frame); // center it over the main JFrame
dialog.setVisible(true); // and display it
}
}));
就在添加第一个按钮的位置下方。您还需要 DisposeWindowAction class,它允许按钮关闭并处理显示它的 window(这里是 JDialog window):
import java.awt.Component;
import java.awt.Window;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.SwingUtilities;
@SuppressWarnings("serial")
public class DisposeWindowAction extends AbstractAction {
public DisposeWindowAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(ActionEvent e) {
Component component = (Component) e.getSource();
if (component == null) {
return;
}
Window win = SwingUtilities.getWindowAncestor(component);
if (win == null) {
return;
}
win.dispose();
}
}