我尝试将自定义Java JPanel导出到PNG文件时遇到了一个有趣的问题。我到目前为止所写的组件的出口过程完美无瑕。
我的JPanel包括自定义编写的JComponents(例如,覆盖paintComponent(Graphics g)并写下我所拥有的内容)。
导出过程如下(我所拥有的扩展JPanel):
public void export(File file, int width, int height)
throws IOException
{
Dimension size = getSize();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = image.createGraphics();
draw (g2, new Rectangle (0, 0, width, height));
try {
ImageIO.write(image, "png", file);
} catch (FileNotFoundException e) {
throw new IOException ("Unable to export chart to ("
+ file.getAbsolutePath() + "): " + e.getLocalizedMessage());
} finally {
g2.dispose();
}
}
上面的'draw()'方法会导致使用要导出的图像的新大小重新绘制所有JPanel的子组件。效果很好。
我今天遇到的问题是我有一个自定义JPanel,其中包含一些Swing组件(包装JEditorPane的JScrollPane)。这个JPanel包含我的一个自定义JComponents,然后是第二个带有JScrollPane的JComponent。
当我执行导出时,大约75%的时间,第二个带有JScrollPane的JComponent在导出的图像中没有正确定位。它位于Point(0,0)处,大小与屏幕上的大小相同。此JComponent的'draw()'方法如下所示:
public void draw(Graphics2D g2, Rectangle componentArea) {
scrollPane.setBounds(componentArea);
textArea.setText(null);
sb.append("<html>");
sb.append("<h1 style=\"text-align:center;\">" + "XXXXXXXXX XXXXXXX" + "</h1>");
textArea.setText(sb.toString());
super.paintComponents(g2);
}
但是大约有25%的时间可以工作 - 带有滚动窗格的这个JComponent正确定位在我导出的图像中。重新绘制成分。
就像有一些双缓冲在这里,我无法搞清楚......
想法?
答案 0 :(得分:0)
您是否通过任何更改修改自定义组件中提供的Graphics对象的Transform对象?如果您确实先保存它然后为您的目的修改新实例,那么在完成后,请将旧的Transform设置回来。
答案 1 :(得分:0)
我会尝试调用paint()方法,而不是paintComponents()。
可能是因为您正在设置编辑器窗格的文本,因此当您尝试绘制组件时,文本未正确解析并且Document未处于最终状态。或者可能是因为您动态设置组件的边界,您遇到了问题。尝试在swingUtilities.invokeLater()中包装super.paint()方法。
ScreenImage类是我用来创建图像的。但我总是用它来创建静态GUI的图像。也就是说,在尝试创建图像的同时,我不会改变组件的边界。
答案 2 :(得分:0)
Swing组件的布局通常是懒惰而不是立即发生,因此可能导致您的间歇性行为。您可以尝试直接调用scrollPane.doLayout() - 通常这是一个坏主意,但它应该保证在绘制之前布置scrollPane。
另外,对于绘制到屏幕外的图像,您应该调用printAll(g)而不是paintComponents(g),因为这样可以避免双重缓冲问题。
答案 3 :(得分:0)
找到解决方案!!你对“安排绘画活动”的评论在我脑海里响了一下。几年前我遇到过这样的问题并忘了这件事。老年人会这样做....
解决方案是将'draw()'方法包装在'SwingUtilities.invokeAndWait()'中。瞧!我的'export()'方法现在看起来像:
public void export(File file, final int width, final int height)
throws IOException
{
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2 = image.createGraphics();
// Must wait for the bloody image to be drawn as Swing 'paint()' methods
// merely schedule painting events. The 'draw()' below may not complete
// the painting process before the 'write()' of the image is performed.
// thus, we wait....
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
draw (g2, new Rectangle (0, 0, width, height));
}
});
ImageIO.write(image, "png", file);
} catch (FileNotFoundException e) {
throw new IOException ("Unable to export chart to ("
+ file.getAbsolutePath() + "): " + e.getLocalizedMessage());
} catch (InterruptedException e) {
e.printStackTrace();
throw new IOException ("Unable to export chart to ("
+ file.getAbsolutePath() + "): " + e.getLocalizedMessage());
} catch (InvocationTargetException e) {
e.printStackTrace();
throw new IOException ("Unable to export chart to ("
+ file.getAbsolutePath() + "): " + e.getLocalizedMessage());
} finally {
g2.dispose();
}
}
呼!