JavaSwing:主类等待JFrame关闭



我需要一个简单的java应用程序的帮助,该应用程序使用两个jframe来获取一些输入参数。这是我的代码草图:

//second jframe, called when the button OK of the first frame is clicked
public class NewParamJFrame extends JFrame{
  ...
}
//first jframe
public class StartingJFrame extends JFrame{
  private static  NewParamJFrame newPFrame = null;
  private JTextField gnFilePath;
  private JButton btnOK;
  public StartingJFrame(){
            //..
    initComponents();
  }
  private void initComponents(){
     btnOK.addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent e){
        try{
        EventQueue.invokeAndWait(new Runnable(){
           public void run() {
               try {
               newPFrame = new NewParamJFrame();
               newPFrame.setVisible(true);
               } catch (Exception e) {
               e.printStackTrace();
               }
           }
         });
        }
        catch(InvocationTargetException e2) {} 
        catch(InterruptedException e1){}
        dispose();
      }
  }
  public String getText(){
       return gnFilePath.getText();
  }
}
public class Main {
  private static StartingJFrame begin = null;
  public static void main(String[] args) {
     try{
        EventQueue.invokeAndWait(new Runnable(){
            public void run() {
                try {
                    begin = new StartingJFrame();
                    begin.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    catch(InvocationTargetException e) {} 
    catch(InterruptedException e1){}
    String s= begin.getText();
    //...use s ...
  }
}

对getText()的调用会导致NullPointerException。我希望主类等到框架关闭,但我不知道该怎么做。我是第一次使用swing。

我希望主类等到框架关闭,但我没有知道怎么做。我是第一次用秋千。

如果我正确理解您的问题,那么您需要StartingJFrame等待NewParamJFrame关闭,然后继续执行。如果是这种情况,那么它就不会发生,因为JFrame不支持模态。但是JDialog有,所以您可以只有一个JFrame,并在父级为JFrameJDialog中进行参数请求。

要更好地解释情态,请阅读"如何在对话框中使用情态"。

还可以看看这个主题:多个JFrame的使用,好的/坏的实践?

无论如何,您可能会面临一个新问题:如果用户在没有输入任何参数的情况下关闭/取消对话框,JFrame应该怎么办?这个JFrame怎么会知道刚才在对话中发生了什么?在这个答案中描述了一种方法。你会看到这个例子是关于登录对话框的,但问题与这个类似:对话框如何通知其父框架进程的进展?

在不修改代码流的情况下等待关闭的最简单方法是使用模式JDialog。因此,您必须更改StartingJFrame类,使其成为JDialog的子类,而不是JFrame,并在其构造函数的开头添加以下内容:

super((Window)null);
setModal(true);

然后StartingJFrame实例上的setVisible(true);调用将等待,直到对话框关闭,因此invokeAndWait调用也将等待。

对getText()的调用会导致NullPointerException。

因为,JTextFieldgnFilePath就是null

private JTextField gnFilePath;
public String getText(){
       return gnFilePath.getText();// NullPointerException is throw here.
}

为了避免NPE,您需要初始化JTextFieldJButton,如下所示。

  private JTextField gnFilePath=new JTextField();
  private JButton btnOK=new JButton()

试着放这个:

import java.awt.event.*;
import javax.swing.*;
public class MyWindow extends JFrame{
    MyWindow(){
        setSize(300, 200);
        setLayout(null);    
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        JButton b = new JButton("Close");
        b.setBounds((300-80)/2, (200-30)/2, 80, 30);
        //
        final MyWindow frame = this;
        b.addActionListener(
            new ActionListener(){
                @Override
                public void actionPerformed(ActionEvent ev){
                    synchronized(frame){
                        frame.notify();
                    }
                
                    frame.setVisible(false);
                    frame.dispose();
                }
            }
        );
        //
        getContentPane().add(b);
        
        setVisible(true);
        
        synchronized(this){
            try{ 
                this.wait();
            }
            catch(InterruptedException ex){ }
        }
    }

    public static void main(String args[]) {
        new MyWindow();
        System.out.println("You are here");
    }
}

已检查上面的代码。

使用JDialog可能是最简单的解决方案,但在某些情况下,最好有一个JFrame,例如在任务栏中显示窗口。使用Octavio建议的同步机制是实现这一点的一种方法,这里有一种使用CountDownLatch阻塞主线程直到帧关闭的替代方法:

public static void main(String[] args) throws Exception {
    CountDownLatch latch = new CountDownLatch(1);
    SwingUtilities.invokeLater(() -> {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        frame.setSize(300, 200);
        frame.setVisible(true);
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosed(WindowEvent e) {
                latch.countDown();
            }
        });
    });
    latch.await();
    System.out.println("Main thread released");
}

您可以使用循环(最好是do-while循环)来保持一个帧,直到另一个帧关闭或隐藏。当其他帧被释放或隐藏时,请确保打断循环或将用于循环的变量增加特定的量。通过这种方式,您可以将StartingJFrame类保留为JFrame的子类。

    do {
        if (changeLog.isVisible()) {
        } else {
            changeLog.dispose();
            break;
        }
    } while (hold < 1);

    do {
        if (changeLog.isActive()) {
        } else {
            break;
        }
    } while (hold < 1);

第一个将要求在运行代码之前隐藏前一帧(JFrame.HIDE_ON_EXITWindow.setVisible(false))。最后一个需要"丢弃"前一帧(JFrame.DISPOSE_ON_EXIT(subclass of JFrame).dispose())。不过,在StartingJFrame上添加任何这些代码,因为您在该类中创建了NewParamJFrame,并将相应的字段设置为private