背景SwingWorker线程不执行特定的代码段

时间:2014-11-15 19:08:49

标签: java multithreading swing debugging swingworker

我无法找到更好的方式在问题标题中表达问题,但希望您能理解......

我有以下代码......

[...]
final JDialog waitingDialog = optionPane.createDialog(optionPane, "Processing in backgroung");

waitingDialog.setLocationRelativeTo(homeFrame);
waitingDialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);


SwingWorker<Void, Void> backgroundThread = new SwingWorker<Void, Void>() {

    @Override
    protected Void doInBackground() throws Exception {
        // Background processing is done here
        System.out.println("[DEBUG] -- Background processing has started");
        MyCustomClass.initParameters();
        System.out.println("DEBUG] -- initParameters() has finished. Starting main processing now...");
        waitingDialog.setVisible(true);
        MyCustomClass.run();
        return null;
    }

    // This is called when background thread above has completed
    @Override
    protected void done() {
        waitingDialog.dispose();
    };
};
backgroundThread.execute();

[and does other things after this...]

...执行得很好直到达到MyCustomClass.run()。当它应该启动这种方法时,它根本就不会这样做。该应用程序不会暂停,停止或崩溃...它只是在后台处理完成后继续等待继续,这种情况不会发生。

MyCustomClass.run()是在static处的MyCustomClass方法。我怀疑问题可能是它的名字 - 运行 - 所以我把它改成了一些随机的东西,如&#34; doIt()&#34;,但问题仍然存在。 该方法的第一行是一个简单的System.out.println("I got here"),但即使是打印也没有。 我在方法调用之前和之后添加了断点并尝试调试,但这也没有帮助。一切似乎都很好,我无法找到问题。


修改
我问:如何在我希望它显示时才能显示对话框?换句话说,脚本是:

  1. 显示&#34;等待&#34;启动SwingWorker时的对话框
  2. 当initParameter()发出需要用户输入的选项对话框时(按一个按钮),隐藏/停止/禁用/配置对话框;
  3. 在处理恢复时再次显示等待对话框
  4. 处理对话框,因为后台处理已完成

3 个答案:

答案 0 :(得分:5)

立刻离开了蝙蝠,我发现你正在SwingWorker的doInBackground中进行Swing调用,这完全违背了使用SwingWorker或后台线程的目的。此外,您正在进行的通话,显示模式对话框:

waitingDialog.setVisible(true); // **** here ****
MyCustomClass.run();   // **** not sure what this does or if this makes Swing calls or not.

将暂停其下方的所有代码流,直到对话框不再可见,因为这是模态对话框的功能。这就是阻止你的SwingWorker的原因。您必须尝试分离代码,以便仅在Swing事件线程上进行Swing调用,并仅将worker用于后台工作。

相反

  • 创建您的SwingWorker
  • 执行您的SwingWorker
  • 然后在模态对话框中调用setVisible(true)

在伪代码中:

create modal dialog
create SwingWorker
Attach any PropertyChangeListeners to the SwingWorker (if needed)
Execute the SwingWorker
Display the modal dialog

因此,我在上面的代码中进行的第一次快速更改是从您的SwingWorker waitingDialog.setVisible(true);方法中删除doInBackground(),然后调用waitingDialog.setVisible(true);方法 AFTER 执行SwingWorker,即在backgroundThread.execute()之后;特别是。我知道在让它显现之前调用dispose似乎是违反直觉的,但相信我,它会更好地运行,因为dispose调用将被运行所需的时间阻塞后台主题​​。

答案 1 :(得分:2)

首先,我接受了@Hovercraft Full Of Eels的回答,因为它确实帮助了我。就像我在评论中所说&#34; 简单地将SwinkWorker中的setVisible(true)替换为其定义之后,使程序按预期流动&#34;,这要归功于他的解释

但是,我需要更多一点(在原始问题的&#34;编辑&#34;部分中描述为脚本)。我设法通过以下代码实现了所需的行为......

final JOptionPane optionPane = new JOptionPane("<html>Please wait...<br>Initializing parameters</html>", JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION,
                    new ImageIcon(Home.class.getResource("/path/to/a/gif/loading.gif")), new Object[]{}, null);

            final JDialog waitingDialog = optionPane.createDialog(optionPane, "MyApp");
            waitingDialog.setLocationRelativeTo(homeFrame);
            waitingDialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);


            SwingWorker<Void, Void> backgroundThread1 = new SwingWorker<Void, Void>() {
                @Override
                protected Void doInBackground() throws Exception {
                    System.out.println("[DEBUG] -- Background processing of initParameters() has started");
                    MyCustomClass.initParameters();
                    System.out.println("[DEBUG] -- initParameters() has finished. Moving on...");
                    return null;
                }

                @Override
                protected void done() {
                    waitingDialog.setVisible(false);
                    optionPane.setMessage("<html>Please wait... <br>Now working on your thing.</html>");
                };
            };
            backgroundThread1.execute();
            waitingDialog.setVisible(true);

            SwingWorker<Void, Void> backgroundThread2 = new SwingWorker<Void, Void>() {
                @Override
                protected Void doInBackground() throws Exception {
                    System.out.println("[DEBUG] -- Start now the main processing in background");
                    MyCustomClass.run();
                    return null;
                }

                @Override
                protected void done() {
                    waitingDialog.dispose();
                };
            };
            backgroundThread2.execute();
            waitingDialog.setVisible(true);

基本上(很明显)我所做的只是创建一个新的SwingWorker并让每个例程在其中一个例程中运行。第一个完成后,它所做的只是隐藏(setVisible(false))&#34; waitingDialog&#34; - 所以主要线程没有被阻止 - 并且在第二个JOptionPane开始后再次显示对话框时,更改对话框使用的SwingWorker消息

我不知道这是否是一种好的,甚至是最好的/最聪明的方式,但它是有效的。如果有更好的方法,我会很高兴了解它。

我只有一个问题尚未解决。在MyCustomClass.run()例程期间的某个地方,某个执行它的第二个SwingWorker正被杀死/终止。 我怎么知道它正在发生?好吧,出于其他调试原因,我的例程中有一个循环在更新时打印某个值,然后突然停止打印(不,循环没有达到它的结束),&#34 ; waitingDialog&#34;消失,没有别的事情发生。该应用程序不会崩溃或任何事情。我可以继续使用它,好像什么也没发生过一样。没有抛出任何异常。

我不知道这是怎么发生的。任何帮助将不胜感激。

答案 2 :(得分:1)

众所周知,Swingworker会在后台线程中吞下运行时异常。您可以通过在Swingworker的done()方法中执行“get()”来检测它们。搜索“SimpleSwingWorker”,您将找到如何执行此操作的示例。