如何让代码等待 GUI 完成?

4
我知道有一个与Matlab相关的类似问题,但对于Java并没有帮助。我正在为一个程序编写GUI,其中一个GUI框架的结果对另一个GUI框架是必要的-我已将我的问题简化为以下内容:
我有一个带有JTextField的GUI JFrame,当按下按钮时,返回字段内容作为字符串。
在静态main方法中,此字符串用于其他方法-尽管在此演示中仅将其放入打印语句中。
我遇到的问题是,代码在继续执行下一条语句之前没有等待GUI完成(即等待某人按下按钮并触发事件)-因此,在这个演示问题中,它会导致“null”被打印,在我的更大的问题中,它会导致null传递给其他JFrames(并引发异常)。
我在线上学到的是,这是由Swing的“多线程”性质引起的-每次创建Swing组件时,它都在自己的线程中运行,以使其余代码可以继续运行-但在这种情况下,我不希望其余代码继续运行,我想我想要的是(我可能错了),所有其他线程都等待当前的Swing线程完成并给出可以在程序中进一步使用的结果。
我可以使用哪些代码来使代码暂停,直到单击GUI的JButton?
我知道解决此问题的一个方法是在代码的ActionListener部分中“嵌套”依赖代码,但在较大的项目中,这会给我带来大量嵌套的代码,这似乎不是一件好事。
主方法的演示问题代码在此处:
public class Testing {

public static void main(String[] args) {

    Testing runningClass = new Testing();
    String message = null;

    JGetString getString = new JGetString();
    message = runningClass.initiateListener(getString);

    System.out.println(message); // How can I make this wait until getString
                                    // has closed?

}

private String initiateListener(JGetString window) {
    buttonListener listener = new buttonListener(window);
    window.addActionListener(listener);
    return listener.returning;

}

public class buttonListener implements ActionListener {

    JGetString getString;
    String returning;

    public buttonListener(JGetString getString) {
        this.getString = getString;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String returning = getString.returnString();
        this.returning = returning;
        getString.setVisible(false);

    }

}

}

我的GUI代码扩展了JFrame,这里是代码:

public class JGetString extends JFrame {
private JTextField textField;
private JButton btnGet = new JButton("Get");

public JGetString() {
    textField = new JTextField();
    getContentPane().add(textField, BorderLayout.CENTER);
    getContentPane().add(btnGet, BorderLayout.SOUTH);
    setVisible(true);
    pack();
}


public void addActionListener(ActionListener act) {
    btnGet.addActionListener(act);

}

public String returnString() {
    return textField.getText();
}


}

非常抱歉问题这么长,代码块也很大 - 谢谢!


1
你可以使用内置方法进行输入 JOptionPane.showInputDialog - user2575725
1个回答

3
正如Arvind在评论中指出的那样:当您想要“等待GUI”时,常见方法是使用对话框。特别是模态对话框。可以使用JOptionPane的实用程序方法创建预定义的标准对话框。更多信息可以在http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html找到。
对话框通常不是一个“真正的窗口”。例如,它没有任务栏中的表示。如果您想创建一个真正的JFrame并等待它关闭,事情可能会变得有点棘手:实际上应该在事件分派线程上执行帧的创建。
因此,为了找到适当的解决方案,您应该非常清楚地了解哪个线程负责什么,哪个线程应该在哪个点等待另一个线程。
通过“职责”,我指的是每个类所扮演的角色。例如:让ActionListener在这里扮演主动角色可能是可行的(也可能更容易)。ActionListener可以调用主类中的一个方法,并将字符串传递给该方法。这将允许主线程和事件分派线程之间进行轻松同步(可能,但最好不要使用synchronizedwait()notifyAll())。
然而,另一种解决方案,在这种解决方案中ActionListener仍保持“被动”,实际字符串仍从JGetString实例中获得,这里描绘了它:引入了一个Waiter类,它只封装了一个CountDownLatch,因此允许等待按钮被按下。但请注意,根据您的长期目标以及程序背后的一般结构和意图,可能会有更合适的解决方案。
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.CountDownLatch;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class WaitForGUI
{
    public static void main(String[] args)
    {
        WaitForGUI waitForGUI = new WaitForGUI();

        String message = waitForGUI.getStringFromGUI();
        System.out.println(message); 

    }

    private JGetString getString = null;    
    private Waiter waiter;

    public WaitForGUI()
    {
        // Create the synchronization aid that will
        // allow waiting for the `JGetString` to 
        // be closed
        waiter = new Waiter();

        // Create the GUI on the Event Dispatch Thread
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                getString = new JGetString();

                ButtonListener listener = new ButtonListener(getString);
                getString.addActionListener(listener);

                getString.addActionListener(waiter);
            }
        });
    }

    // This method will block until the button in 
    // the `JGetString` was pressed.
    String getStringFromGUI()
    {
        waiter.waitFor();
        return getString.returnString();
    }


    private class ButtonListener implements ActionListener
    {
        JGetString getString;

        public ButtonListener(JGetString getString)
        {
            this.getString = getString;
        }

        @Override
        public void actionPerformed(ActionEvent e)
        {
            getString.setVisible(false);
        }
    }

    private static class Waiter implements ActionListener
    {
        private final CountDownLatch latch = new CountDownLatch(1);

        @Override
        public void actionPerformed(ActionEvent e)
        {
            latch.countDown();
        }

        void waitFor()
        {
            try
            {
                latch.await();
            }
            catch (InterruptedException e)
            {
                Thread.currentThread().interrupt();
            }
        }
    }
}

class JGetString extends JFrame
{
    private JTextField textField;
    private JButton btnGet = new JButton("Get");

    public JGetString()
    {
        textField = new JTextField();
        getContentPane().add(textField, BorderLayout.CENTER);
        getContentPane().add(btnGet, BorderLayout.SOUTH);
        setVisible(true);
        pack();
    }

    public void addActionListener(ActionListener act)
    {
        btnGet.addActionListener(act);

    }

    public String returnString()
    {
        return textField.getText();
    }

}

非常感谢!我会查看这个以及之前提到的对话框! - davidhood2

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