Java 如何在Swing应用程序中在后台加载图像?
我有一个简单的Swing/AWT应用程序,在Windows上以全屏模式运行。我有两个不同的PNG文件,它根据上下文加载为自己的背景图像 它像这样加载它们:Java 如何在Swing应用程序中在后台加载图像?,java,swing,awt,Java,Swing,Awt,我有一个简单的Swing/AWT应用程序,在Windows上以全屏模式运行。我有两个不同的PNG文件,它根据上下文加载为自己的背景图像 它像这样加载它们: BufferedImage bufferedImage; bufferedImage = ImageIO.read(getClass().getResource("/bg1.png")); Image bgImage1 = bufferedImage.getScaledInstance(width, height, Image.SCALE_S
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.repaint();
graphics.drawImage(bgImage2, 0, 0, null);
// draw some other stuff too, like text
然后画成这样:
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.repaint();
graphics.drawImage(bgImage2, 0, 0, null);
// draw some other stuff too, like text
更详细地说,window
是一个JWindow
变量,graphics
是一个Graphics2D
变量
我遇到的问题发生在我将一个背景图像切换到另一个背景图像时。第一次切换时,我会这样叫:
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.repaint();
graphics.drawImage(bgImage2, 0, 0, null);
// draw some other stuff too, like text
…整个屏幕变白约一秒钟。然后它成功地显示了图像,但是闪烁真的很烦人。我的猜测是,由于图像相对较大且分辨率较高(2560x1440),因此需要大约一秒钟的时间来加载图像并将其缩放到适当的大小
如何让它以静默方式加载这些图像?如。。。如何避免在第一次显示新的背景图像时,在一秒钟内绘制一个空白的白色屏幕?所有随后的时间都是瞬间的,可能是因为它真的在那个时候把它们记在了记忆中。但是仅仅调用
getScaledInstance
显然不足以将内容放入内存,因为在我调用drawImage
之前,它实际上不会闪烁。我注意到缩放需要很多时间,而不是加载图像。
正因为如此,我通常会存储一个缩放的图像,以便以后使用,所以我只需缩放一次 将作为功能加载到后台
您也可以通过后台线程轻松完成此任务,例如:
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();
这让我有点担心。通常,我们不需要要求对整个顶级容器进行重新喷漆。您也不应该使用getGraphics()
进行绘制
非顶级Swing组件是双缓冲的,但如果在绘制结构外部进行绘制,则不会得到此效果。它将导致闪烁
正确定制绘画的两个良好来源是:
应通过在JComponent上覆盖paintComponent
被动地完成绘制。JLabel还可以将图像图标显示为一项功能,因此如果您只想显示图像,则不必进行自定义绘制。那么,为什么我在调用drawImage
之前没有注意到闪烁?当我的应用程序初始化时,我立即缩放所有三幅图像,然后显示其中一幅。但直到几分钟后,当我在另外两个屏幕中的一个上调用drawImage
时,我才第一次看到那个白色屏幕;GraphicsDevice screen=ge.getDefaultScreenDevice();JWindow window=新的JWindow();window.setVisible(true);Graphics2D graphics=(Graphics2D)window.getGraphics()代码>是,这将导致闪烁以及其他异常问题。自定义绘画需要在 PruttCys 中完成。您应该考虑提供一个演示您的问题的可运行示例。您可能遇到的一个问题是,您并没有将ImageObserver传递给drawImage方法。。。