Как я могу отклонить один JOptionPane при появлении другого JOptionPane в графическом интерфейсе

Как вы видели из моей темы выше,
я хотел бы знать, как я могу отклонить JOptionPane, который стал неактуальным из-за другого 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                   

}

person JavaSa    schedule 16.10.2011    source источник
comment
JOptionPane обычно является модальным (конечно, есть исключения), поэтому мне интересно, как пользователь вообще смог вызвать вторую JOptionPane, когда первая видна? Можете ли вы создать и опубликовать небольшую компилируемую и работающую программу, которая демонстрирует вашу проблему и которую мы можем протестировать, изменить и, возможно, исправить, sscce?   -  person Hovercraft Full Of Eels    schedule 17.10.2011
comment
Хорошо, я создал очень простой рабочий пример, куда мне его загрузить?   -  person JavaSa    schedule 17.10.2011
comment
@JavaSa: отредактируйте свой пост и включите его.   -  person Nate W.    schedule 17.10.2011
comment
Спасибо за ваш SSCCE. Я изменил код в своем ответе ниже.   -  person Hovercraft Full Of Eels    schedule 17.10.2011


Ответы (3)


я бы порекомендовал вам

  • создайте JDialog с помощью JOptionPane (JOptionPane APIпокажу как)
  • затем используйте SwingWorker для любой фоновой задачи, которую вы хотите выполнить, которая должна выполняться вне основного потока Swing, EDT,
  • Затем в методе SwingWorker done(), который вызывается после завершения фоновой задачи, удалите файл JDialog.
  • Затем немедленно будет вызван следующий JOptionPane.

Например, следующий код использует Thread.sleep(3000) для 3-секундного сна, чтобы имитировать фоновую задачу, которая занимает 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);
   }
person Hovercraft Full Of Eels    schedule 16.10.2011
comment
Я предполагаю, что мне не нужен свинг-воркер, потому что моя фоновая задача выполняется на моем сервере, после того, как она проверила доску, она возвращает одобренный Ack клиентскому графическому интерфейсу, и игра автоматически начинается. - person JavaSa; 17.10.2011
comment
Я не уверен, что вам не понадобится SwingWorker или какой-то фоновый поток. Как ваш код графического интерфейса сообщает серверу о необходимости проверки платы? Это делает это блокирующим способом или неблокирующим способом? Как графический интерфейс ожидает ответа сервера? Как уведомляется? Все эти вещи могут связать ваш поток событий Swing. Но,... это ваше приложение, так что делайте так, как считаете нужным. - person Hovercraft Full Of Eels; 17.10.2011
comment
Хорошо, я пытаюсь прояснить ситуацию: когда мой графический интерфейс сначала подключается к моему серверу, он открывает новый поток прослушивания (работающую реализацию) в клиенте, который ожидает прихода команды в DataInputStream, простым вызовом функции readInt для члена m_InputStream. . Графический интерфейс говорит серверу проверить доску на специальном экране построения доски после нажатия кнопки качания, подтвердите доску, она блокируется, потому что мне нужно, чтобы второй игрок за столом построил свою собственную доску для оппонента, и только затем - person JavaSa; 17.10.2011
comment
начать игру, когда две доски были построены обоими игроками, сидящими рядом с игровым столом. так что это блокирует, я думаю, мне не нужно, чтобы мой графический интерфейс реагировал после отправки, просто нужно подождать, поэтому я не думаю, что загрузка моей доски после нажатия кнопки подтверждения приведет к тому, что графический интерфейс не будет отвечать, вызвать все эти действия очень быстро, как вы думаете? - person JavaSa; 17.10.2011
comment
Если они очень быстрые, то нет необходимости в JOptionPane, чтобы сказать игроку ждать проверки. В противном случае вам понадобится фоновый поток. Но только вы можете сказать. Если ваша программа заметно зависает в какой-то момент, это указывает на необходимость в потоке. В любом случае, удачи! - person Hovercraft Full Of Eels; 17.10.2011
comment
Нет, ожидание, когда соперник закончит построение своей доски для вас, а не только подтверждение подтверждения вашей собственной доски. Только когда две доски были проверены, они одновременно отправляются сервером каждому клиенту двух игроков путем скрещивания каждой доски, созданной пользователями для своих соперников, и игра начинается. Я предполагаю, что не каждый код быстрой связи, который запускается из JbuttonActionPerformed (EDT), является запрещенным действием. Я прав? В любом случае, здесь немного поздно, поэтому я попробую завтра и сообщу вам :) - person JavaSa; 17.10.2011
comment
+1, это хорошая альтернатива, хотя этот ответ поставил меня в замешательство, когда я отвечал в другой ветке :-), я использовал Timer вместо SwingWorker, поэтому удивляюсь, что мой подход плохой :-) - person nIcE cOw; 07.08.2013

простой ответ, это невозможно, потому что в настоящее время может существовать только один JOptionPane, если вы хотите решить свою проблему, вам нужно создать JDialog#ModalityType(Aplications???) или 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();
            }
        });
    }
}
person mKorbel    schedule 16.10.2011
comment
хорошо, спасибо, но как насчет использования некоторых манипуляций, как в принятом ответе сообщения stackoverflow.com/questions/4542924/ , решит ли это мою проблему? - person JavaSa; 17.10.2011
comment
Я думаю, поскольку может существовать только одна панель JoptionPane, этот пост не может помочь - person JavaSa; 17.10.2011
comment
@JavaSa 1) в основном можно скрыть JOptionPane, 2) никто не гарантирует, какой блок кода будет выполняться текущий или предыдущий из скрытого JOptionPane, 3) этот компонент предназначен для блокировки выполнения кода (работает как семафор), блокирует user_input, 4) последнее свойство для вызова (настраиваемый JOptionPane с добавленными вручную JButton(s)) myButton.doClick();, затем JOptionPane исчез 5) Я думаю, что это ничего не решает (ссылка, которую вы разместили) :-) - person mKorbel; 17.10.2011

Извините, я плохо понимаю ваш вопрос, вы имеете в виду, что хотите закрыть одну 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();
        }
    }
}
person Eng.Fouad    schedule 16.10.2011
comment
Нет, я имел в виду, что если пользователь недостаточно быстр, чтобы нажать «ОК» на одной панели JoptionPane, она останется в фоновом режиме, через некоторое время он получит другую панель параметров, а затем ему нужно будет закрыть две панели JoptionPane, поэтому я хочу иметь возможность отменить предыдущие JoptionPane, если этот второй JoptionPane уже вошел (и пользователь не отклонил первый) - person JavaSa; 17.10.2011