java - 如何让代码等待 GUI 完成?

标签 java eclipse multithreading swing user-interface

我知道有一个与 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 可以调用主类中的方法,并将字符串传递给该方法。这将允许在主线程和事件调度线程之间轻松同步(可能,但最好不要使用 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();
    }

}

关于java - 如何让代码等待 GUI 完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22959558/

相关文章:

java - hibernate 连接问题

java - hibernate 不读取 ehcache.xml 或不超时?

java - 无法将应用程序见解裸 API 添加到 Java Web 应用程序

java - 多线程从数据库优化中选择行

python - 使用 python 和 matplotlib 同时获取数据和更新图形

java - ConcurrentHashMap#putIfAbsent 但删除项目(如果存在)

java - map 或flatMap内的RxJava Single.error

Java:如何创建一个仅在其实例不存在时启动并在实例存在时调用该实例的应用程序?

java - 使用 Maven 构建时 JasperReports 找不到字体

android - 我如何使用 eclipse 从 android 写入控制台