Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何判断Graphics.drawImage()何时实际完成_Java_Image_Awt_Java 2d - Fatal编程技术网

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

Java 如何判断Graphics.drawImage()何时实际完成,java,image,awt,java-2d,Java,Image,Awt,Java 2d,这是我第一次在这里提问,我希望我能得到一个对我有帮助的答案或想法 我正在绘制一个大图像,并使用drawImage()将其缩小。然后,我立即用drawImage()绘制另一幅图像,我希望它是在前一幅(第二幅)的基础上绘制的。问题是drawImage会立即返回,即使缩放和渲染第一幅图像需要约50毫秒。大多数情况下,第二个图像最终位于第一个图像的下方,因为它是在第一个大图像正在处理时首先绘制的。基本上,是强制drawImage()阻塞直到它完成,还是以某种方式检查它何时完成 我知道ImageObser

这是我第一次在这里提问,我希望我能得到一个对我有帮助的答案或想法

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

我知道ImageObserver参数,它在从Internet或其他地方下载图像时可以正常工作,但在使用已加载的BuffereImage时,它不会在缩放和绘制之后触发ImageUpdate()。基本上,因为第一个图像已经“加载”,它从不联系ImageObserver,它只需要在自己的线程中处理大约50毫秒,不会在完成时通知

是否有人知道如何强制它阻止或等待,直到它完全完成缩放和光点图像?显然,使用Thread.sleep(xx)是一种完全的黑客行为,由于计算机速度的不同,它是不可行的。所有这些渲染都发生在paint(Graphics g)方法内部的事件线程上

谢谢

编辑:以下是我目前必须向您介绍的代码:

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

drawImage
(传递null)的最后一个参数是
ImageObserver
。如果您提供该接口()的自己实现,则在实际绘制图像时将通知您。

不可能知道Swing何时实际将
图形
对象的内容呈现到屏幕上。我们所知道的是,在
绘制
方法返回之前,它不会发生(因为
图形
对象在返回之前尚未完成渲染)

您应该做的是让正在绘制的
组件
决定什么时候需要更新,这就是它的设计方式…(
组件
实现
图像观察者

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

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
,而选择使用
JApplet
,事实上,我个人会避免使用Applet或两者一起使用。我开始了编写小程序的职业生涯,它们只是一种痛苦,尤其是当你只想测试一个想法的时候。

我做过这件事,但那不起作用。正如我在第二段中所解释的,我已经实现了ImageObserver和imageUpdate()方法,并且实现了System.out.println(“Fired”);如果有人叫过,但从来没有人叫过。我将final drawImage()参数从null改为this。但是如果图像已经预计算并准备好绘制,drawImage将返回true(并且不会通知ImageObserver)。你查过了吗?drawImage是否真的立即返回真值而不实际绘制图像?这正是问题所在。它确实返回true(因为它在read-in中被“加载”并被转换),但是它仍然会立即返回,即使它需要大约100毫秒的时间来缩小它的大小并进行blit。到那时,第二个小图像已经被不整洁地(错误地)显示。imageUpdate()从未被调用。在这里,我添加了第二个可以复制/粘贴的示例,它将演示这个问题。在第二个示例中,您在绘制方法的末尾调用repaint(),从而触发立即重新绘制,从而引发无休止的重新绘制循环。闪烁使我无法看到哪个图像是先画的。如果删除重绘调用,则首先缩放并绘制第一个图像,然后再在其顶部绘制小图像(如预期的那样)。第一次调用drawImage大约需要130毫秒,第二次调用需要0.06毫秒。在Windows上使用OracleJDK1.7.0_07进行测试。我无法确定Java何时会实际渲染图形对象的输出。您可以确定的一件事是,直到paint方法返回后才会发生,因此Thread.sleep除了降低程序的速度之外什么都不做。如果要通过某种组件进行绘制,请将其作为ImageObserver传递给drawInage方法,并让它在准备好后进行自我更新。另一种选择是在后台线程
public class Main extensed Applet..
中缩放图像,因为此Applet使用的图像不在本地磁盘上,因此该线程在此处不起作用。人们运行小程序也比运行应用程序困难。我建议你发布一个基于框架的图片,或者是图片的热链接,或者是用代码生成图片。