java - 将 JComponent 绘制为一项长期任务

标签 java multithreading swing paintcomponent swingworker

  1. 与 Swing JComponent 的所有交互都必须在事件调度线程中完成。也画画。
  2. 长任务必须在事件调度线程之外运行,否则会阻塞 GUI。

但是如果长时间任务是在 Graphics2D 中绘制应用程序(例如 1000 次)怎么办?这是否有冲突的要求?

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

如果我需要多次调用此方法,可以将其视为一项长期任务,我应该怎么做才能避免阻塞 GUI?据我了解,不允许将其委托(delegate)给 SwingWorker。对于这种“长期任务”有什么解决方法吗?

最佳答案

我认为这是一个异常(exception)。只要您不绘制到屏幕上,就可以在后台线程中调用它。重点是实际的 UI 内容应该发生在事件分派(dispatch)线程上,以便用户可以看到所有更改。

这是如何发生这种情况的框架:

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) {
        // ...
    }
}

我只能看到一个警告:在此打印过程中 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);
                }
            }
        });
    }
}

第二种方法一次运行一个 paintComponent(),因此不会卡住您的 UI。这就是为什么它不需要任何执行程序或工作线程。它只是确保它添加

关于java - 将 JComponent 绘制为一项长期任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43982682/

相关文章:

java - 系统化的 getter 和 setter 但需要避免死锁

multithreading - storm 中的哪个类会实例化每个 bolt 和喷口的线程数?

java - 如何使 Java 组合框中的项目居中

c++ - 为什么这个函数级静态变量在 AIX 和 Solaris 中不是线程安全的?

java - 通过 jt400 将文本文件写入 IFS 时出现问题

java - 空虚是什么意思?

java - 使用java解析json数据

java - 为什么我的 2D 迷宫没有用 JComponent 绘制?

java - 我正在尝试从 DateChooserPanel 获取字符串类型的日期并在文本字段上显示日期

java - Java 中多个操作数的按位异或