2

为简单起见,想象一个下载​​文件的应用程序。有一个简单的 GUI,带有一个显示进度的标签。为了避免违反 EDT,像每个合法公民一样,我在一个线程(主)中下载文件,并在另一个线程(EDT)中更新 GUI。因此,这是相关的伪代码块:

class Downloader {
    download() {
        progress.startDownload();
        while(hasMoreChunks()) {
            downloadChunk();
            progress.downloadedBytes(n);
        }
        progress.finishDownload();
    }
}

class ProgressDisplay extends JPanel {
    JLabel label;
    startDownload() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                label.setText("Download started");
            }
        });
    }
    downloadedBytes(int n) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                label.setText("Downloaded bytes: " + n);
            }
        });
    }
    finishDownload() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                label.setText("Download finished");
            }
        });
    }
}

我喜欢 Java 不支持闭包的事实,而且代码对我来说非常清晰。除了笑话,我想知道......我做错了吗?是否有可能在每个方法等中使用SwingUtilities匿名实现来消除所有这些丑陋的样板?Runnable

我的情况比这稍微复杂一些,但我试图通过实现代理或类似的东西来避免过度设计。

4

5 回答 5

2

该任务有专门的课程:SwingWorker. 它允许您在单独的线程中运行代码并在工作结束时更新 UI。

于 2011-06-02T14:51:46.383 回答
1

在不引入大量冗余代码的情况下,您无法避免使用样板代码。但是你可以用一个小的抽象帮助类和一些不寻常的格式让它变得更好一点。

public abstract static class SwingTask implements Runnable
{
    public void start()
    {
         SwingUtilities.invokeLater( this );
    }
}

startDownload() {
    new SwingTask() { public void run() {
        label.setText("Download started");
    } }.start();
}

代码格式旨在强调这一行中的所有代码基本上都是无趣的样板代码,可以轻松安全地复制到需要它的其他地方。我们已经使用这种格式样式有一段时间了,结果证明它非常有用。

于 2011-06-02T15:17:50.440 回答
0

我会使用类似的辅助方法。

 public void setLabelText(final JLabel label, final String text) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            label.setText(text);
        }
    });
 }
于 2011-06-02T14:49:50.493 回答
0

几年前,我们在一个项目中使用了Spin 。

于 2011-06-02T14:58:28.900 回答
0

只是一个原始的想法:

public class ThreadSafeJLabel extends JLabel {

    @Override
    public void setText(final String text) {
        if (SwingUtilities.isEventDispatchThread()) {
            super.setText(text);
        } else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    setText(text);
                }
            });
        }
    }

}

没试过,但我想当setText()从 EDT 调用时,super会被使用;但是当涉及到其他线程时,被覆盖的 ( ThreadSafeJLabel.setText()) 将在稍后被调用,这次是在 EDT 内部。

于 2011-06-02T15:06:43.433 回答