如何判断Graphics.drawImage()实际完成的时间

时间:2013-01-26 01:11:57

标签: java image awt java-2d

这是我第一次在这里问一个问题,我希望得到一个能帮到我的答案或想法。

我正在绘制一个大图像并使用drawImage()缩小它。然后我立即用drawImage()绘制另一个图像,我期望在前一个(第二个)之上绘制。问题是drawImage会立即返回,即使缩放和渲染第一个图像需要大约50毫秒。大多数情况下,第二张图像最终位于第一张图像的下方,因为它首先被绘制,而第一张图像正在被处理。反正基本上是强制drawImage()阻塞直到它完成,或以某种方式检查它何时完成?

我知道ImageObserver参数,当从Internet或其他东西下载图像时它可以正常工作,但是当使用已经加载的BufferedImage时,它只是在缩放和绘制之后才会触发ImageUpdate()。基本上,由于第一个图像已经“加载”,它从不接触ImageObserver,它只需要大约50毫秒的自己的线程来处理,从不通知它何时完成。

有没有人知道如何强制它阻止或等到它完全完成缩放和blitting图像?显然使用Thread.sleep(xx)是一个完整的黑客,由于计算机速度之间的差异而不可行。所有这些渲染都发生在paint(Graphics g)方法中的Event线程上。

谢谢!

编辑:以下是我目前要解释的问题的代码:

public void paint(Graphics window)
{
    window.setColor(Color.WHITE);
    window.fillRect(0, 0, Settings.width * Settings.aaFactor, Settings.height * Settings.aaFactor);

    Graphics2D window2D = (Graphics2D) window;
    window2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    window2D.drawImage(this.image, 0, 0, Settings.width, Settings.height, null);

    try
    {
        Thread.sleep(50);
    }
    catch (InterruptedException e)
    {
        e.printStackTrace();
    }

    window2D.drawImage(this.image2, 0, 0, null);

    repaint();
}

编辑2:为了更好地解释我正在谈论的问题,我制作了一些示例代码,这些代码做得更好,我正在尝试解释。运行它,你会看到它闪烁,有时第一个图像在底部(就像它应该是),但大多数时候它将是一个顶部(第二个),这是错误的。只需将文件路径更改为小图像和大图像。

public class Main extends Applet implements ImageObserver
{
    private BufferedImage imageA;
    private BufferedImage imageB;

    @Override
    public void init()
    {
        try
        {
            this.imageA = ImageIO.read(new File("C:\\LargeImage.jpg"));
            this.imageB = ImageIO.read(new File("C:\\SmallImage.jpg"));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    @Override
    public void update(Graphics g)
    {
        paint(g);
    }

    @Override
    public void paint(Graphics g)
    {
        Graphics2D w = (Graphics2D) g;
        w.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        w.drawImage(this.imageA, 0, 0, 50, 50, this);// This takes a while to do (scaling down and drawing)...
        w.drawImage(this.imageB, 10, 10, null);// While this is drawn quickly, before A is done.

        repaint();
    }

    @Override
    public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
    {
        System.out.println("ImageObserver fired, done drawing image.  NEVER CALLED!");
        return false;
    }
}

2 个答案:

答案 0 :(得分:1)

drawImage的最后一个参数(传递null的地方)是ImageObserver。如果您提供自己的界面实现(see JavaDoc),则会在实际绘制图像时通知您。

答案 1 :(得分:1)

无法知道Swing何时会将Graphics对象的内容实际渲染到屏幕上。知道的是,在paint方法返回之后才会发生这种情况(因为Graphics对象尚未完成渲染,直到它完成)。

你应该做的是让你正在绘制的Component来决定什么时候需要更新,这是它的设计方式......(Component实现{{1 }})

以下示例在调整帧大小时连续重新缩放主背景图像

enter image description here

ImageObserver

虽然我确定你有理由,但我个人会避免public class TestPaint03 { public static void main(String[] args) { new TestPaint03(); } public TestPaint03() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception ex) { } JFrame frame = new JFrame("Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new PaintPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class PaintPane extends JPanel { private BufferedImage background; private BufferedImage foreground; private Image scaled; public PaintPane() { try { background = ImageIO.read(new File("/path/to/background/image)); foreground = ImageIO.read(new File("path/to/foreground/image")); } catch (Exception e) { } } @Override public void invalidate() { scaled = null; super.invalidate(); } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); if (background != null) { if (scaled == null) { int size = Math.min(getWidth(), getHeight()); scaled = background.getScaledInstance(-1, size, Image.SCALE_SMOOTH); } int x = (getWidth() - scaled.getWidth(this)) / 2; int y = (getHeight() - scaled.getHeight(this)) / 2; g.drawImage(scaled, x, y, this); x = (getWidth() - foreground.getWidth()) / 2; y = (getHeight() - foreground.getHeight()) / 2; g.drawImage(foreground, x, y, this); } } } } 支持Applet,事实上,我个人会避免使用applet。我开始编写applet的职业生涯,他们只是一种痛苦,特别是当你想要做的就是测试一个想法时。