【发布时间】:2013-01-10 01:31:09
【问题描述】:
这是我第一次在这里提出问题,希望能得到对我有帮助的答案或想法。
我正在绘制一个大图像并使用 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;
}
}
【问题讨论】:
-
我无法确定 Java 何时会真正呈现 Graphics 对象的输出。您可以确定的一件事是它不会在paint方法返回之后发生,因此 Thread.sleep 除了减慢您的程序速度之外什么也不做。如果您正在通过某种组件进行绘画,请将其作为 ImageObserver 传递给 drawInage 方法,并在准备好时让它自行更新。另一种选择是在后台线程中缩放图像
-
public class Main extends Applet..这在这里不起作用,因为这个小程序使用了不在本地磁盘上的图像。 Applet 也比应用程序更难运行。我建议你发布一个基于 SSCCE 的框架,它可以热链接到图像或在代码中生成它们。