[英]How to tell when Graphics.drawImage() has actually completed
这是我第一次在这里问一个问题,我希望得到一个能帮到我的答案或想法。
我正在绘制一个大图像并使用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;
}
}
drawImage
的最后一个参数(传递null的地方)是一个ImageObserver
。 如果您提供自己的接口实现( 请参阅JavaDoc ),则会在实际绘制图像时通知您。
无法知道Swing何时实际将Graphics
对象的内容呈现给屏幕。 知道的是,直到paint
方法返回之后才会发生这种情况(因为Graphics
对象在渲染之前尚未完成渲染)。
你应该做的是让你正在绘制的Component
决定什么时候需要更新,这是它的设计方式...( Component
实现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
支持JApplet
,事实上,我个人会避免使用applet。 我开始编写applet的职业生涯,他们只是一种痛苦,特别是当你想要做的就是测试一个想法时。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.