如何在GUI中出现另一个JOptionPane时关闭一个JOptionPane?

6

从我的主题中可以看出,我想知道如何关闭一个JOptionPane,因为另一个JOptionPane变得无关紧要,而用户由于某种原因没有通过点击ok按钮(例如)自己关闭第一个JOptionPane。

我在其他网站上看到了类似的问题,并且有人建议简单地执行以下操作:

JOptionPane.getRootFrame().dispose();  

但是我该如何为每个JOptionPane存储一个引用,并且只能关闭想要关闭的那个。
谢谢
编辑:
代码示例:
package Gui;

import javax.swing.JOptionPane;
import java.awt.*;

/**
 *
 * @author 
 */
public class JpanelMainView extends javax.swing.JPanel {

    /** Creates new form JpanelMainView */
    public JpanelMainView() {
        initComponents();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jButton1 = new javax.swing.JButton();

        jButton1.setText("jButton1");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(149, 149, 149)
                .addComponent(jButton1)
                .addContainerGap(178, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(77, 77, 77)
                .addComponent(jButton1)
                .addContainerGap(200, Short.MAX_VALUE))
        );
    }// </editor-fold>                        

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)                                         
    {                                             
       JOptionPane.showMessageDialog(this, "Board was sent for validation check\n Please wait...","Board Sent",JOptionPane.INFORMATION_MESSAGE);

       //Please note that this OptionPane is coming in my real program always after the first JoptionPane
       //I want that if I've reached the line in the code that need to show this second JoptionPane, I will first close the first JoptionPane
       //Else you will dismiss the last JoptionPane and then the first one and I don't want to give the user two JoptionPane to close, it's annoying.
       JOptionPane.showMessageDialog(this, "Set your move now please","Game started",JOptionPane.INFORMATION_MESSAGE);
    }                                        

    // Variables declaration - do not modify                     
    private javax.swing.JButton jButton1;
    // End of variables declaration                   

}

1
一个JOptionPane通常是模态的(当然也有例外),所以我想知道当第一个JOptionPane可见时,用户如何能够弹出第二个JOptionPane?你能否创建并发布一个小的可编译和可运行的程序来演示你的问题,以便我们可以测试、修改和可能纠正它,一个sscce - Hovercraft Full Of Eels
好的,我已经生成了一个非常简单的工作示例,我应该上传到哪里? - JavaSa
1
@JavaSa:编辑你的帖子并将其包含在内。 - Nate W.
1
感谢您提供的SSCCE。我已经修改了下面答案中的代码。 - Hovercraft Full Of Eels
3个回答

8
我建议您:
  • 使用JOptionPane创建JDialog(JOptionPane API可以帮助您实现)
  • 然后使用SwingWorker执行任何应该在主Swing线程之外完成的后台任务
  • 最后在SwingWorker的done()方法中处理完后台任务后,关闭JDialog。
  • 这样,下一个JOptionPane将会立即显示。
例如,以下代码使用Thread.sleep(3000)模拟需要3秒钟才能完成的后台任务。完成后,它将关闭第一个对话框并显示第二个对话框:
   private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
      JOptionPane messagePane = new JOptionPane(
            "Board was sent for validation check\n Please wait...",
            JOptionPane.INFORMATION_MESSAGE);
      final JDialog dialog = messagePane.createDialog(this, "Board Sent");

      new SwingWorker<Void, Void>() {

         @Override
         protected Void doInBackground() throws Exception {
            // do your background processing here
            // for instance validate your board here

            // mimics a background process that takes 3 seconds
            // you would of course delete this in your actual progam
            Thread.sleep(3000); 

            return null;
         }

         // this is called when background thread above has completed.
         protected void done() {
            dialog.dispose();
         };
      }.execute();

      dialog.setVisible(true);

      JOptionPane.showMessageDialog(this, "Set your move now please",
            "Game started", JOptionPane.INFORMATION_MESSAGE);
   }

我想我不需要 Swing Worker,因为我的后台任务正在我的服务器中进行。在验证了游戏版之后,它会向客户端 GUI 返回一个“ok”确认信号,游戏会自动开始。 - JavaSa
我不确定您是否不需要SwingWorker或某种后台线程。您的GUI代码如何告诉服务器验证棋盘?它是以阻塞方式还是非阻塞方式进行的?GUI如何等待服务器的响应?它是如何通知的?所有这些事情都可能卡住您的Swing事件线程。但是......这是您的应用程序,您可以按照自己的意愿进行操作。 - Hovercraft Full Of Eels
如果程序非常快,那么就不需要使用JOptionPane来告诉玩家等待验证。否则,你将需要一个后台线程。但只有你自己能判断。如果你的程序在任何时候明显地冻结,那就说明需要一个线程。无论如何,祝你好运! - Hovercraft Full Of Eels
不,等待是为了对手玩家完成他的游戏板——而不是仅仅为了验证你自己的游戏板。只有当两个游戏板都得到验证后,它们才会被服务器同时发送给两位玩家,以交叉方式交换彼此建立的游戏板,从而开始游戏。我猜并不是每一个从JbuttonActionPerformed(EDT)启动的快速通信代码都是违规行为,我说的对吗?无论如何,这里已经有点晚了,所以我明天再试一下,然后再更新你 :) - JavaSa
+1,这是一个不错的替代方案,虽然这个答案让我有些困惑,在回答另一个线程时,我使用了一个 Timer 而不是 SwingWorker,所以在想我的方法是否不好 :-) - nIcE cOw
显示剩余2条评论

4

简单回答,这是不可能的,因为同一时间只能存在一个 JOptionPane,如果你想解决你的问题,那么你必须创建 JDialog#ModalityType(应用程序???)JWindow,然后你将能够显示 JOptionPane

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ClosingFrame extends JFrame {

    private JMenuBar MenuBar = new JMenuBar();
    private JFrame frame = new JFrame();
    private static final long serialVersionUID = 1L;
    private JMenu File = new JMenu("File");
    private JMenuItem Exit = new JMenuItem("Exit");
    private JFrame frame1 = new JFrame();

    public ClosingFrame() {
        File.add(Exit);
        MenuBar.add(File);
        Exit.addActionListener(new ExitListener());
        WindowListener exitListener = new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                int confirm = JOptionPane.showOptionDialog(frame,
                        "Are You Sure to Close this Application?",
                        "Exit Confirmation", JOptionPane.YES_NO_OPTION,
                        JOptionPane.QUESTION_MESSAGE, null, null, null);
                if (confirm == 0) {
                    System.exit(1);
                }
            }
        };
        frame.addWindowListener(exitListener);
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.setJMenuBar(MenuBar);
        frame.setPreferredSize(new Dimension(400, 300));
        frame.setLocation(100, 100);
        frame.pack();
        frame.setVisible(true);

        frame1.addWindowListener(exitListener);
        frame1.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame1.setPreferredSize(new Dimension(400, 300));
        frame1.setLocation(500, 100);
        frame1.pack();
        frame1.setVisible(true);
    }

    private class ExitListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            int confirm = JOptionPane.showOptionDialog(frame,
                    "Are You Sure to Close this Application?",
                    "Exit Confirmation", JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE, null, null, null);
            JOptionPane.showMessageDialog(null, "Whatever", "Whatever",
                    JOptionPane.ERROR_MESSAGE);
            int confirm1 = JOptionPane.showOptionDialog(frame1,
                    "Are You Sure to Close this Application?",
                    "Exit Confirmation", JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE, null, null, null);
            if (confirm == 0) {
                //System.exit(1);
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                ClosingFrame cf = new ClosingFrame();
            }
        });
    }
}

好的,谢谢。但是像这篇帖子中的答案(https://dev59.com/wFLTa4cB1Zd3GeqPe_Nh)中提到的一些操作方法,是否可以解决我的问题呢? - JavaSa
我猜因为只能存在一个JOptionPane,所以那个帖子无法帮助。 - JavaSa
1
@JavaSa 1) 基本上可以隐藏 JOptionPane,2) 没有人保证哪个代码块将被执行,当前或之前的隐藏 JOptionPane,3) 这个组件用于阻塞代码执行(作为信号量),阻止用户输入,4) 最后一个属性是调用(自定义 JOptionPane 并手动添加 JButton(s))myButton.doClick(),然后 JOptionPane 就消失了。5) 我认为这解决了什么(你发布的链接):-) - mKorbel

3
抱歉,我不太明白您的问题,您是想从另一个JOptionPane中关闭一个JOptionPane吗?请提供更多信息。
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class GUIProgram extends JFrame implements ActionListener
{
    private JButton btn1, btn2, btn3;
    private static final String BUTTON1_COMMAND = "Press it!";
    private static final String BUTTON2_COMMAND = "show new JOptionPane!";
    private static final String BUTTON3_COMMAND = "close old JOptionPane!";
    private JOptionPane pane1, pane2;

    public GUIProgram()
    {
        super("The title");
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        btn1 = new JButton(BUTTON1_COMMAND);
        btn1.addActionListener(this);
        btn1.setActionCommand(BUTTON1_COMMAND);

        btn2 = new JButton(BUTTON2_COMMAND);
        btn2.addActionListener(this);
        btn2.setActionCommand(BUTTON2_COMMAND);

        btn3 = new JButton(BUTTON3_COMMAND);
        btn3.addActionListener(this);
        btn3.setActionCommand(BUTTON3_COMMAND);

        pane1 = new JOptionPane();
        pane2 = new JOptionPane();

        getContentPane().add(btn1);
        setSize(200, 100);
        setVisible(true);
    }

    public static void main(String args[])
    {
        new GUIProgram();
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        if(e.getActionCommand().equals(BUTTON1_COMMAND))
        {
            JPanel panel = new JPanel();
            panel.add(btn2);
            pane1.showOptionDialog(null, panel, "JOptionPane #1", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, new Object[]{}, null);
        }

        else if(e.getActionCommand().equals(BUTTON2_COMMAND))
        {
            JPanel panel = new JPanel();
            panel.add(btn3);
            pane2.showOptionDialog(null, panel, "JOptionPane #2", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, new Object[]{}, null);
        }

        else if(e.getActionCommand().equals(BUTTON3_COMMAND))
        {
            pane1.getRootFrame().dispose();
        }
    }
}

不,我的意思是如果用户无法快速点击一个JOptionPane上的“确定”按钮,它将留在后台,过一段时间后他将会得到另一个JOptionPane,然后他将需要关闭两个JOptionPane,因此我希望能够取消先前的JOptionPane,如果第二个JOptionPane已经出现(并且用户没有关闭第一个)。 - JavaSa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接