- 与 Swing JComponent 的所有交互都必须在事件调度线程中完成。也画画。
- 长任务必须在事件调度线程之外运行,否则会阻塞 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/