我知道在Matlab方面也有类似的问题,但这对我的Java没有帮助。我正在为一个程序编写GUI,其中一个GUI帧的结果对于另一个GUI框架是必要的——我已经将我的问题简化为以下内容:
我有一个带有 JTextField
的GUI JFrame
,当按下按钮时,它会以字符串的形式返回字段的内容。
在staticmain方法的后面,这个字符串用于其他方法——尽管在本演示中,它只是被放入一个print语句中。
我遇到的问题是,代码没有等待GUI完成(也就是某人按下按钮并触发事件),然后再继续执行下一条语句——因此,在这个演示问题中,它会导致打印"null",而在我的更大问题中,会导致null传递给其他JFrame(并引发异常)。
我在网上学到的是,这是由于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);
}
}
}
扩展 JFrame
的GUI代码如下:
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();
}
}
很抱歉有这么长的问题和大量的代码,谢谢!
正如Arvind在评论中指出的那样:当你想"等待GUI"时,一种常见的方法是对话框。特别是模式对话框。预定义的标准对话框可以使用JOptionPane
的实用程序方法创建。更多信息,请访问http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html
对话框通常不是"真正的窗口"。例如,它在任务栏中没有表示形式。如果您想创建一个真正的JFrame
,并等待它关闭,事情可能会变得有点麻烦:实际上,帧的创建应该在事件调度线程上完成。
因此,为了找到合适的解决方案,您应该清楚地知道哪个线程负责什么,哪个线程应该在哪个点等待哪个其他线程。
所谓"责任",我指的是每个班级所扮演的角色。例如:让ActionListener
在这里发挥积极作用可能是一个可行的(可能更容易)解决方案。ActionListener
可以调用主类中的一个方法,并将字符串传递给该方法。这将允许主线程和事件调度线程之间的简单同步(可能,但最好不要,与synchronized
、wait()
和notifyAll()
同步
然而,另一个解决方案,其中ActionListener
保持"被动",并且实际字符串仍然是从JGetString
实例中获得的,在这里进行了概述:它引入了一个仅封装CountDownLatch
的Waiter
类,从而允许等待按钮被按下。但是注意根据您的长期目标以及计划背后的总体结构和意图,可能会有更合适的解决方案。
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();
}
}