Java 如何在Swing应用程序中在后台加载图像?

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

我有一个简单的Swing/AWT应用程序,在Windows上以全屏模式运行。我有两个不同的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.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方法。。。