简体   繁体   English

为什么 JFrame 的背景图像仅在我在 Swing 中调整窗口大小后才显示?

[英]Why is a Background Image of a JFrame only showing after i resize the window in Swing?

I have noticed some weird behaviour with setting an image as a background for my JFrames.我注意到将图像设置为 JFrame 的背景时出现了一些奇怪的行为。 I want to have a background image for both Frames display when they are created.我想在创建时为两个框架显示一个背景图像。 When i create Window1 inside my main method it only shows the background after i manually resize the window.当我在主方法中创建 Window1 时,它仅在我手动调整窗口大小后显示背景。 When i click the button in Window1 and create window2 inside Window1, Window2 displays the background image correctly.当我单击 Window1 中的按钮并在 Window1 中创建 window2 时,Window2 正确显示背景图像。 When i create Window2 inside my main method the background image also does not show correctly.当我在主方法中创建 Window2 时,背景图像也无法正确显示。

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class TestStart {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Window1();
            }
        });
    }
}

public class Window1 extends JFrame {

    Image img = Toolkit.getDefaultToolkit().getImage("C:\\Users\\Tim\\Desktop\\water.jpg");

    public Window1() {
        super("gridtest");

        setSize(600, 500);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        this.setContentPane(new JPanel(){
            public void paintComponent(Graphics g){
                super.paintComponent(g);
                g.drawImage(img,0,0,getWidth(),getHeight(),null);
            }
        });

        JButton btn = new JButton("klick");
        add(btn, BorderLayout.CENTER);

        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                new Window2();
            }
        });
        pack();
        setVisible(true);
    }
}

public class Window2 extends JFrame {

    Image img = Toolkit.getDefaultToolkit().getImage("C:\\Users\\Tim\\Desktop\\water.jpg");

    public Window2() {
        super("gridsecond");

        setSize(600, 500);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        this.setContentPane(new JPanel(){
            public void paintComponent(Graphics g){
                super.paintComponent(g);
                g.drawImage(img,0,0,getWidth(),getHeight(),null);
            }
        });
        pack();
        setVisible(true);
    }
}

I tried adding in revalidate()/repaint() calls and calling the paint method at different points in my code, but except for the weird behaviour i described above, i cant get the background image to show without resizing my window.我尝试添加 revalidate()/repaint() 调用并在我的代码中的不同点调用paint方法,但除了我上面描述的奇怪行为之外,我无法在不调整窗口大小的情况下显示背景图像。

Disclaimer: I know it's not good practice to create a new JFrame for every window, but i am not able to change the whole project structure, so im stuck with this.免责声明:我知道为每个窗口创建一个新的 JFrame 不是一个好习惯,但我无法改变整个项目结构,所以我坚持这个。

So, a series of issues that might be causing your issue...因此,一系列可能导致您出现问题的问题...

First, using Toolkit.getDefaultToolkit().getImage首先,使用Toolkit.getDefaultToolkit().getImage

Image img = Toolkit.getDefaultToolkit().getImage("C:\\Users\\Tim\\Desktop\\water.jpg");

The problem with this is, the image loading is down on a seperate thread.问题是,图像加载在一个单独的线程上。 This means that when getImage returns the image may or may not have actually been loaded这意味着当getImage返回时,图像可能已经或可能没有被实际加载

Second, when calling drawImage , you pass null as the ImageConsumer , so the component won't be notified of changes to the images "loaded" state and won't be able to schedule updates to the component accordingly...其次,在调用drawImage ,您将null作为ImageConsumer传递,因此组件不会收到图像“加载”状态更改的通知,并且无法相应地安排对组件的更新......

this.setContentPane(new JPanel(){
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(img,0,0,getWidth(),getHeight(),null);
    }
});

Three, this is more of a side effect, but, you've set the contentPane manually using a JPanel , which by default uses a FlowLayout , so using BorderLayout constraints is actually kind of pointless.三,这更多的是副作用,但是,您已经使用JPanel手动设置了contentPane ,默认情况下使用FlowLayout ,因此使用BorderLayout约束实际上是毫无意义的。

setLayout(new BorderLayout());

this.setContentPane(new JPanel(){
//...
JButton btn = new JButton("klick");
add(btn, BorderLayout.CENTER);

Besides, BorderLayout is the default layout manager used by window based components ;)此外, BorderLayout是基于窗口的组件使用的默认布局管理器 ;)

So, how would you fix this issue?那么,你将如何解决这个问题? Well, immediately, you could pass this as the ImageConsumer ...好吧,立即,您可以将this作为ImageConsumer传递...

g.drawImage(img,0,0,getWidth(),getHeight(),this);

This will allow the component to monitor the loading state of the image and trigger repaints as required.这将允许组件监视图像的加载状态并根据需要触发重绘。

A longer term solution would be to stop using Toolkit.getDefaultToolkit().getImage (and by extension, ImageIcon ), as they can be annoying, and start using ImageIO instead.一个长期的解决方案是停止使用Toolkit.getDefaultToolkit().getImage (以及扩展名ImageIcon ),因为它们可能很烦人,并开始使用ImageIO

Apart from supporting a wider range of image formats, the API won't return till the image is fully loaded or an error occurred (try diagnose loading issues with the other APIs 🙄)除了支持更广泛的图像格式外,API 在图像完全加载或发生错误之前不会返回(尝试使用其他 API 诊断加载问题🙄)

See Reading/Loading images for more details有关更多详细信息,请参阅读取/加载图像

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM