【问题标题】:How can I make code wait for a GUI to finish?如何让代码等待 GUI 完成?
【发布时间】:2014-05-22 11:29:14
【问题描述】:

我知道有一个关于 Matlab 的类似问题,但它对 Java 没有帮助。我正在为一个程序编写一个 GUI,其中一个 GUI 框架的结果对于另一个 GUI 框架是必需的 - 我已将我的问题简化为以下问题:

我有一个带有 JTextField 的 GUI JFrame ,当按下按钮时,它会以字符串形式返回字段的内容。

在静态 main 方法的下方,此字符串用于其他方法 - 尽管在此演示中它只是放入了一个 print 语句。

我遇到的问题是代码在继续执行下一条语句之前没有等待 GUI 完成(也就是有人按下按钮并触发事件) - 因此在这个演示问题中它导致“null”要打印,在我更大的问题中,它会导致 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);

    }

}

}

我的 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();
}


}

对于这么长的问题和大量的代码,我们深表歉意 - 非常感谢!

【问题讨论】:

标签: java eclipse multithreading swing user-interface


【解决方案1】:

正如 Arvind 在评论中已经指出的那样:当您想要“等待 GUI”时,一种常见的方法是 对话框。特别是 modal 对话框。可以使用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();
    }

}

【讨论】:

  • 非常感谢!将调查这个和前面提到的对话框!
猜你喜欢
  • 2020-02-10
  • 1970-01-01
  • 1970-01-01
  • 2021-12-23
  • 2020-11-22
  • 2020-09-18
  • 2017-11-28
  • 1970-01-01
  • 2023-04-04
相关资源
最近更新 更多