我有一个在Windows上以全屏模式运行的简单Swing / AWT应用程序。我有几个不同的PNG文件,它根据上下文加载为自己的背景图像。
它像这样加载它们:
BufferedImage bufferedImage;
bufferedImage = ImageIO.read(getClass().getResource("/bg1.png"));
Image bgImage1 = bufferedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
bufferedImage = ImageIO.read(getClass().getResource("/bg2.png"));
Image bgImage2 = bufferedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
bufferedImage = ImageIO.read(getClass().getResource("/bg3.png"));
Image bgImage3 = bufferedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
后来把它们画成这样:
window.repaint();
graphics.drawImage(bgImage1, 0, 0, null);
// draw some other stuff too, like text
为了彻底,window
是JWindow
变量,graphics
是Graphics2D
变量。
当我将一张背景图片换成另一张背景图片时,我遇到的问题就发生了。我第一次进行切换时,调用这样的东西:
window.repaint();
graphics.drawImage(bgImage2, 0, 0, null);
// draw some other stuff too, like text
......整个屏幕变白了大约一秒钟。然后它确实成功显示了图像,但闪烁真的很烦人。我的猜测是,因为图像相对较大且分辨率较高(2560x1440),所以需要大约一秒钟来加载它们并将它们缩放到合适的大小。
如何让它静静加载这些图像?如...在第一次显示新的背景图像时,如何避免画一个空白的白色屏幕?随后的所有时间都已经是瞬间的,可能是因为它在那时真正抓住了它们。但是简单地调用getScaledInstance
显然不足以将内容放入内存中,因为在我调用drawImage
之前它实际上并没有闪烁。
答案 0 :(得分:2)
ImageIcon
将作为功能在后台加载。
您也可以使用后台线程轻松完成此操作,例如:
final String path = "/example.png";
new SwingWorker<BufferedImage, Void>() {
@Override
public BufferedImage doInBackground() throws IOException {
return ImageIO.read(ClassName.class.getResource(path));
}
@Override
public void done() {
try {
BufferedImage img = get();
// put img somewhere
} catch(InterruptedException ignored) {
} catch(ExecutionException ex) {
ex.printStackTrace(System.err);
}
}
}.execute();
此外,
window.repaint();
graphics.drawImage(bgImage2, 0, 0, null);
这让我有点担心。通常,我们不需要请求整个顶级容器的repaint
。您也不应该使用getGraphics()
来绘画。
非顶级Swing组件是双缓冲的,但如果你在绘画结构之外绘画,你就不会得到它。它会导致闪烁。
正确定制绘画的两个好消息来源是:
绘画应该通过覆盖JComponent上的paintComponent
来被动地完成。 JLabel还可以将ImageIcon显示为一项功能,因此如果您只想显示图像,则无需进行自定义绘制。
答案 1 :(得分:0)
我注意到缩放需要花费大量时间,而不是加载图像。 因此,我通常存储缩放的图像,以便稍后使用它,所以我只需要缩放一次。