JFrame仅在首次创建时显示组件

时间:2014-08-20 00:56:55

标签: java multithreading swing components swingworker

当我启动我的应用程序时,它会打开JFrame(主窗口)和JFilechooser以选择输入目录,然后扫描该目录。

扫描方法本身会创建一个包含JFrameJButton的新JProgressBar,并启动一个扫描所选目录的新线程。到目前为止一切正常。

现在我在主窗口中更改目录路径,再次调用扫描方法。这次它创建了另一个JFrame,其中应包含JProgressBarJButton,但它显示为空(JFrame标题仍然设置。)

更新: 最小的例子

public class MainWindow
{
    private JFrame      _frame;
    private JTextArea   _textArea;
    private ProgressBar _progress;

    public MainWindow() throws InterruptedException, ExecutionException
    {
        _frame = new JFrame("Main Window");
        _textArea = new JTextArea();

        _frame.add(_textArea);
        _frame.setSize(200, 200);
        _frame.setVisible(true);

        _textArea.setText(doStuffinBackground());

        _progress.dispose();
    }

    private String doStuffinBackground() throws InterruptedException,
            ExecutionException
    {
        setUpProgressBar();
        ScanWorker scanWorker = new ScanWorker();
        scanWorker.execute();

        return scanWorker.get();
    }

    private void setUpProgressBar()
    {
        // Display progress bar
        _progress = new ProgressBar();
    }

    class ProgressBar extends JFrame
    {
        public ProgressBar()
        {
            super();

            JProgressBar progressBar = new JProgressBar();
            progressBar.setIndeterminate(true);
            progressBar.setStringPainted(false);

            add(progressBar);

            setTitle("Progress Window");
            setSize(200, 200);
            toFront();
            setVisible(true);
        }
    }

    class ScanWorker extends SwingWorker<String, Void>
    {
        @Override
        public String doInBackground() throws InterruptedException
        {
            int j = 0;
            for (int i = 0; i < 10; i++)
            {
                Thread.sleep(1000);
                j += 1;
            }
            return String.valueOf(j);
        }
    }

    public static void main(String[] args) throws InvocationTargetException,
            InterruptedException
    {
        SwingUtilities.invokeAndWait(new Runnable()
        {
            public void run()
            {
                // Start the main controller
                try
                {
                    new MainWindow();
                }
                catch (InterruptedException | ExecutionException e) {}
            }
        });
    }
}

1 个答案:

答案 0 :(得分:2)

scan方法的基本外观来看,当您扫描目录时阻止了事件调度线程,这阻止了它更新UI。

具体来说,您似乎并不真正了解CallableFutureTask实际使用的内容或如何正确使用它们......

调用FutureTask#run将从当前线程上下文中调用Callable的{​​{1}}方法....

请查看Concurrency in Swing了解更多详情......

不要试图以这种方式使用callFutureTask,而是考虑使用Callable,它旨在执行此类工作(并使用SwingWorker和内部Callable

有关详细信息,请查看Worker Threads and SwingWorker

现在,在你跳下我的喉咙并告诉我“它第一次运行它”时,这是因为你没有正确启动你的UI。应该在Event Dispatching Thread的上下文中创建和操作所有Swing UI。你执行FutureTask方法,通常称为“主线程”,它与EDT不同。这基本上设置了第一次调用main时的侥幸情况,你没有在EDT的上下文中运行,允许它工作......并且在这个过程中打破了Swing的单线程规则。 ..

请查看Initial Threads了解更多详情......

我还会考虑使用scan代替另一个框架,即使它不是模态的,它也可以为您的应用程序提供更好的范例,因为它实际上应该只有一个主框架。

根据新代码更新

所以,基本上,JDialog是一个阻止调用。它将等到return scanWorker.get();方法完成,这意味着它阻止了EDT,仍然......“

相反,您应该使用doInBackground

publishprocess和/或done方法

Worker

SwingWorker