0

我在尝试将自定义 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 组件(一个 JScrollPane 包装了一个 JEditorPane)。这个 JPanel 包括我的一个自定义 JComponent,然后是第二个 JComponent,上面有 JScrollPane。

大约 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 正确定位在我导出的图像中。重新绘制组件作品。

就像这里发生了一些我无法弄清楚的双重缓冲......

想法?

4

4 回答 4

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

哇!

于 2010-08-27T17:03:42.653 回答
0

Swing 组件的布局通常是懒惰而不是立即发生,因此可能会导致您的间歇性行为。您可以尝试直接调用 scrollPane.doLayout() - 通常这是一个坏主意,但它应该保证在您绘制它之前布局 scrollPane。

此外,对于绘制到屏幕外的图像,您可能应该调用 printAll(g) 而不是 paintComponents(g),因为这样可以避免双缓冲问题。

于 2010-08-27T09:14:06.697 回答
0

我会尝试调用paint() 方法,而不是paintComponents()。

可能是因为您正在设置编辑器窗格的文本,所以当您尝试绘制组件时,文本没有被正确解析,并且 Document 未处于最终状态。或者可能是因为您正在动态设置您遇到问题的组件的边界。尝试将 super.paint() 方法包装在 SwingUtilities.invokeLater() 中。

ScreenImage类是我用来创建图像的但我一直用它来创建静态 GUI 的图像。也就是说,我不会在尝试创建图像的同时更改组件的边界。

于 2010-08-27T02:42:15.630 回答
0

您是否通过任何更改修改自定义组件中提供的 Graphics 对象的 Transform 对象?如果您确实确保首先保存它,然后为您的目的修改一个新实例,当您完成后,将旧的转换设置回来。

于 2010-08-26T21:28:09.430 回答