Swing 线程安全样板

发布于 2024-11-12 21:28:08 字数 1207 浏览 4 评论 0原文

为了简单起见,想象一个下载​​文件的应用程序。有一个简单的 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 的匿名实现等消除所有这些丑陋的样板?

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

For the sake of simplicity, imagine an application that downloads a file. There is a simple GUI with one label that displays progress. To avoid EDT violations, like every lawful citizen I download the file in one thread (main), and update GUI in another (EDT). So, here's the relevant chunk of pseudcode:

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");
            }
        });
    }
}

I love the fact that Java does not support closures and the code is crystal clear to me. Jokes aside, I'm wondering... Am I doing it wrong? Is it possible to eliminate all this ugly boilerplate with SwingUtilities, anonymous implementation of Runnable in every method etc.?

My case is slightly more complicated than this, but I'm trying not to overengineer by implementing proxies or something like that.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

寂寞笑我太脆弱 2024-11-19 21:28:09

有一个用于该任务的特殊类: SwingWorker< /代码>。它允许您在单独的线程中运行代码并在工作结束时更新 UI。

There is special class for that tasks: SwingWorker. It allows you yo run code in a separate thread and update UI on the end of the work.

生生漫 2024-11-19 21:28:09

如果不在其他地方引入大量冗余代码,您无法做太多事情来避免样板代码。但是您可以通过一个小的抽象帮助器类和一些不寻常的格式使其变得更好一点。

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

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

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

There is not much you can do to avoid the boilerplate code without introducing a lot of redundant code elsewhere. But you can make it a little bit nicer with a small abstract helper class and some unusual formatting.

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

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

The code formatting is meant to emphasize that all the code in this single line is basically uninteresting boilerplate code that can easily and safely be copied to other places where it is needed. We have been using this formatting style now for a while and it turned out quite useful.

煮酒 2024-11-19 21:28:09

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

 public void setLabelText(final JLabel label, final String text) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            label.setText(text);
        }
    });
 }

I would use a helper method like.

 public void setLabelText(final JLabel label, final String text) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            label.setText(text);
        }
    });
 }
半岛未凉 2024-11-19 21:28:09

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

We used Spin in a project a few years back.

跨年 2024-11-19 21:28:09

只是一个原始想法:

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);
                }
            });
        }
    }

}

还没有尝试过,但我想当从 EDT 调用 setText() 时,将使用 super ;但是当涉及其他线程时,重写的 (ThreadSafeJLabel.setText()) 将稍后调用,这次是在 EDT 内。

Just a raw idea:

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);
                }
            });
        }
    }

}

Haven't tried it but I guess when called setText() from EDT, super will be used; but when other thread is involved, the overridden (ThreadSafeJLabel.setText()) will be called later, this time inside EDT.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文