我知道有一个与 Matlab 相关的类似问题,但它对 Java 没有帮助。我正在为一个程序编写 GUI,其中一个 GUI 框架的结果对于另一个 GUI 框架是必需的 - 我已将我的问题简化为以下内容:
我有一个带有 JTextField
的 GUI JFrame
,当按下按钮时,它以字符串形式返回字段的内容。
在静态 main 方法的下方,此字符串用于其他方法 - 尽管在本演示中它只是放入打印语句中。
我遇到的问题是代码在继续执行下一条语句之前没有等待 GUI 完成(也就是有人按下按钮并触发事件) - 因此在这个演示问题中它导致“空”被打印出来,在我更大的问题中,它导致 null 被传递给其他 JFrame(并抛出异常)。
我在网上了解到,这是由于 Swing 的“多线程”特性 - 每次我创建一个 Swing 组件时,它都在自己的线程中运行,以使其余代码能够继续 -但是在这种情况下,我不希望其余代码继续,我想我想要的(我可能是错的)是所有其他线程等待当前 Swing 线程完成并给出可以是的结果在程序中进一步使用。
我可以使用什么代码来使代码暂停,直到 GUI 的 JButton
被点击?
我知道对此的一种解决方案是将依赖代码“嵌套”在代码的 ActionListener
部分中,但在较大的项目中,这会给我大量的嵌套代码,这似乎并不好东西。
main方法的demo问题代码在这里:
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
,并等待它关闭,事情可能会变得有点麻烦:框架的创建实际上应该在事件上完成调度线程。
因此,为了找到合适的解决方案,您应该真正清楚地了解哪个线程负责什么,哪个线程应该在哪个点等待另一个线程。
“职责”指的是每个类(class)所扮演的角色。例如:让 ActionListener
在这里发挥主 Action 用可能是一个可行(并且可能更容易)的解决方案。 ActionListener
可以调用主类中的方法,并将字符串传递给该方法。这将允许在主线程和事件调度线程之间轻松同步(可能,但最好不要使用 synchronized
、wait()
和 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();
}
}
关于java - 如何让代码等待 GUI 完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22959558/