Java 将组件绘制为一项长期任务 与Swing JComponent的所有交互都必须在事件分派线程中完成。我也在画画 长任务必须在事件分派线程之外运行,否则它们将阻塞GUI

Java 将组件绘制为一项长期任务 与Swing JComponent的所有交互都必须在事件分派线程中完成。我也在画画 长任务必须在事件分派线程之外运行,否则它们将阻塞GUI,java,multithreading,swing,paintcomponent,swingworker,Java,Multithreading,Swing,Paintcomponent,Swingworker,但如果长任务是在Graphics2D中绘制应用程序(例如1000次),该怎么办?这是相互冲突的要求吗 public class MyObject extends JPanel { ... public void paintComponent(Graphics g) {...} ... } 如果我需要多次调用这个方法,以至于可以将其视为一个很长的任务,我应该做什么来避免阻塞GUI?据我所知,不允许将其委托给SwingWorker。这种“长任务”有什么解决办法吗?我认为这是

但如果长任务是在Graphics2D中绘制应用程序(例如1000次),该怎么办?这是相互冲突的要求吗

public class MyObject extends JPanel {
    ...
    public void paintComponent(Graphics g) {...}
    ...
}

如果我需要多次调用这个方法,以至于可以将其视为一个很长的任务,我应该做什么来避免阻塞GUI?据我所知,不允许将其委托给SwingWorker。这种“长任务”有什么解决办法吗?

我认为这是个例外。只要不在屏幕上绘制,就可以在背景线程中调用它。关键是,实际的UI内容应该发生在事件分派线程上,这样所有的更改都将对用户可见

这是一个如何实现的框架:

public class MyObject extends JPanel {

    private static final int NUMBER_OF_PDFS = 10_000;

    private JProgressBar progressBar = new JProgressBar(0, NUMBER_OF_PDFS);

    public void paintPdfs() {
        ExecutorService threadPool = Executors.newFixedThreadPool(5); // this can come somewhere else too
        for (int i = 0; i < NUMBER_OF_PDFS; i++) {
            final int newProgressBarValue = i; // you might need some mapping, depends on the setup of the taskbar
            threadPool.execute(() -> {
                try {
                    Graphics pdfG2 = getPdfGraphics();
                    MyObject.this.paintComponent(pdfG2);
                } finally {
                    SwingUtilities.invokeLater(() -> {
                        int progressBarValue = progressBar.getValue();
                        if (progressBarValue < newProgressBarValue) {
                            progressBar.setValue(newProgressBarValue);
                        }
                    });
                }
            });
        }
    }

    private Graphics getPdfGraphics() {
        // I don't know how to do this. On the other hand, you do :)
        return null;
    }

    @Override
    public void paintComponent(Graphics g) {
        // ...
    }
}
公共类MyObject扩展了JPanel{
私有静态最终整数\u的\u PDF=10 \u 000;
私有JProgressBar progressBar=新的JProgressBar(0,PDF的数量);
公共图书馆(PDF){
ExecutorService threadPool=Executors.newFixedThreadPool(5);//这也可以在其他地方出现
for(int i=0;i{
试一试{
Graphics pdfG2=getPdfGraphics();
MyObject.this.paintComponent(pdfG2);
}最后{
SwingUtilities.invokeLater(()->{
int progressBarValue=progressBar.getValue();
if(progressBarValue
我只能看到一个警告:在打印期间,swing对象不应更改。如果他们这样做了,那么你需要另一个技巧。另一个技巧是在事件分派线程中逐个打印PDF:

public void paintPdfs() {
    for (int i = 0; i < NUMBER_OF_PDFS; i++) {
        final int newProgressBarValue = i; // you might need some mapping, depends on the setup of the taskbar
        SwingUtilities.invokeLater(() -> {
            try {
                Graphics pdfG2 = getPdfGraphics();
                MyObject.this.paintComponent(pdfG2);
            } finally {
                int progressBarValue = progressBar.getValue();
                if (progressBarValue < newProgressBarValue) {
                    progressBar.setValue(newProgressBarValue);
                }
            }
        });
    }
}
public-pdfs(){
for(int i=0;i{
试一试{
Graphics pdfG2=getPdfGraphics();
MyObject.this.paintComponent(pdfG2);
}最后{
int progressBarValue=progressBar.getValue();
if(progressBarValue

第二种方法一次运行一个
paintComponent()
,因此不会冻结您的UI。这就是它不需要任何执行器或工作线程的原因。它只是确保它增加了

你能解释一下为什么要花这么多时间吗?它访问数据库吗?它是否调用长时间运行的事务?另一个问题:为什么要运行1000次?你有多少时间来画这1000幅画?计算你所有的数字和形状,在paintComponent方法之外,所以paintComponent方法需要做的就是,嗯,画画。仅绘制一千个对象不太可能影响性能,特别是在一台配备现代视频卡的机器上。@Tamas Rev是的,实际上我绘制我的应用程序10.000多次以生成pdf(只需使用pdf-g2调用paintComponent)。我想在执行此操作时显示一个进度条。
绘制我的应用程序10.000多次以生成PDF
-对我来说毫无意义。为什么要重新绘制10000次才能生成PDF。你在做动画吗?用户永远不会注意到PDF中的10K增量更改。如果您正在生成10K PDF,那么Swing与此有什么关系?我猜PDF是在后台生成和保存的。如果您只想更新进度条,则无需自定义绘制。请阅读上的教程以获得一个工作示例。@camickr实际上,我正在为大量用户制作个性化空白。请不要用“稻草人”这样咄咄逼人和明显。绘制应用程序10k以上的次数可能听起来很奇怪,但仍然是一项可能的任务。首先,
paintComponent
不应该是
public
,它受
保护
出于某种原因,不应该直接调用它,您应该使用专为此类操作而设计的
print
printAll
,禁用一次双缓冲