【问题标题】:Java Swing Program- Input from GUI to Main getting stuckJava Swing 程序 - 从 GUI 到 Main 的输入卡住了
【发布时间】:2014-07-14 10:35:52
【问题描述】:

我有一个 Java 程序,我计划从 GUI 中获取输入,然后使用该输入在 main() 中进行处理。我正在使用Eclipse
我正在向 GUI JFrame 发送一个HW 对象(称为HWObj),并检查对象中的boolean 字段以继续在main() 中处理。

InputWindow 是扩展JPanel 实现ActionListener 的自定义对象 它包含对当前JFrame(parentFrame) 的引用。在 InputWindow 中单击JButton 时,我编写了一个自定义ActionListener,它将HWObj.check 的值设置为true 并处理parentFrame。这应该会导致在main() 中恢复执行。
HW 类的代码如下:

import java.awt.*;
import javax.swing.*;
public class HW {

    //globals
    boolean check;
    public HW() {
        //initialisations
        check = false;
    }

    public static void main(String args[]) { 
        final HW problem = new HW();
        try {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    //Create and set up the window.
                    JFrame frame = new JFrame("Select folders");
                    frame.setPreferredSize(new Dimension(640, 480));
                    frame.setResizable(false);
                    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                    InputWindow Directories = new InputWindow(problem, frame);
                    Directories.setOpaque(true);
                    frame.add(Directories);
                    //Display the window.
                    frame.pack();
                    frame.setVisible(true);
                }
            });
        } catch(Exception e) {
            System.out.println("Exception:"+e.getLocalizedMessage());
        }
        while(!problem.finish);
        //Do processing on problem
        System.out.println("Done");
    } 
}

gui中的Actionlistener如下:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class InputWindow extends JPanel
                implements ActionListener {

    private static final long serialVersionUID = 4228345704162790878L;

    HW problem;
    JFrame parentFrame;
    //more globals

    public InputWindow(HW problem, JFrame parentFrame) {
        super();
        this.setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();

        this.parentFrame = parentFrame;
        this.problem = problem;

        JButton finishButton = new JButton("Finish");
        finishButton.setActionCommand("fin");
        finishButton.addActionListener(this);
        gbc.gridx = 0;
        gbc.gridy = 0;
        this.add(finishButton, gbc);

        //Initialize buttons and text areas and labels
        //Code removed for ease of reading

    }

    public void actionPerformed(ActionEvent e) {
        String command = e.getActionCommand();
        if(command.equals("fin")) {
            //Do a lot of stuff, then   
            this.removeAll();
            parentFrame.dispose();
            problem.check = true;
        }
    }
}

我已经检查过了,这个功能的控制通常是在按钮点击时出现的。

现在,我希望它返回到main,并退出while 循环,然后继续处理。 这不会发生。 eclipse中的调试器只显示主线程正在运行,当我尝试暂停它时,我看到线程卡在while循环中。但是,如果我尝试单步执行,它会按预期退出 while 循环,然后继续。但是,在我手动尝试调试它之前,它一直停留在 while 循环中。
问题是什么?为什么它没有按预期恢复main thread? 我该如何解决这个问题?

【问题讨论】:

  • 需要完整的代码。
  • 完整的代码庞大而臃肿。你能告诉我你想要哪些零件吗?
  • 创建一个新框架然后销毁它的类的代码,以及你在while循环中卡住的那个。
  • “相关”部分会很好。如果您将代码提取到方法中,而不是用代码填充主方法,那么阅读起来会容易得多。 main 方法应该什么都不做,只是启动你的应用程序。
  • 您想要哪些零件? == 发布一个 SSCCE/MCVE,简短、可运行、可编译、生成上午问题

标签: java eclipse swing user-interface user-input


【解决方案1】:

您的问题与 Java 内存模型的工作方式有关。主线程中的循环将检查 check 的陈旧值。

当你进入调试器时,内存被强制更新,这就是它在那个时候开始工作的原因。

如果您将变量标记为volatile,这将强制 JVM 确保所有线程都使用最新值:

volatile boolean check;

您可以在documentation 中阅读有关volatile 和Java 内存模型的更多信息。

【讨论】:

  • 这样的优化发生在 C 中,但你确定这也发生在 Java 中吗?
  • @TSG 这本身不是优化,它更多地与 java 内存模型的工作方式有关。我将进行编辑以澄清。
  • @TSG 仔细想了想,其实我已经彻底改变了解释! (但不是解决方案......):)
  • 谢谢。使用 volatile 解决了这个问题。您是否认为使用 JDialog 会是一种更合适的方法,正如@Hovercraft Full Of Eels 在另一个答案中提出的那样
  • 在这种情况下,JDialog 可以工作,因为它会阻塞设置它可见的线程,直到对话框完成。如果您想在主线程中实际做某事,那是不合适的。您可能还考虑使用不同的方法进行线程间通信,而不是忙于等待 volatile 变量。我会用一个例子来更新我的答案。
【解决方案2】:

看起来您正在使用 JFrame,而您应该使用模态 JDialog。如果您将模态 JDialog 用于输入窗口,您将确切知道它何时“完成”,因为代码流将从对话框设置为可见后立即从调用代码恢复。

如果您尝试交换视图,则使用 CardLayout 交换视图,并使用观察者类型模式来监听状态变化。

【讨论】:

  • 谢谢。我不需要交换意见。在继续之前,我只需要等待输入。我会检查 JDialog
  • @TSG: My dialog is used to get input for a number of directories etc. This data needs to return to main for further computation. -- 那么你应该使用模态 JDialog。但是使用你想要的,因为它是你的项目。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-25
  • 1970-01-01
  • 2012-02-26
  • 1970-01-01
  • 2018-03-02
相关资源
最近更新 更多