从构造函数调用 repaint()

repaint() call from the constructor

我正在尝试显示加载的资源图像。 它有效,但只有在用户调整 window.

的大小之后
import javax.swing.*; import java.awt.*;

class MyMainWindow extends JFrame{
    Image img;

    public MyMainWindow(){
        setSize(300,300);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        img = MyResourceLoader.getImage("res.jpg");
        repaint();

        setVisible(true);
    }
    @Override
    public void paint (Graphics g){
        super.paint(g);
        if (img != null)
            g.drawImage(img, 0,0, null);
    } 
}

public class ResourcesProgram {
    public static void main(String[] args) {
        new MyMainWindow();
    } 
}

为什么构造函数的 repaint() 调用不起作用? 我应该怎么做才能从一开始就显示这张图片?

资源加载器class:

import java.awt.*;

public class MyResourceLoader{
    static MyResourceLoader rl = new MyResourceLoader();
    static public Image getImage(String fileName){
        return Toolkit.getDefaultToolkit().getImage(rl.getClass().getResource("images/" + fileName));
    }
}

好吧,一堆东西...

首先...

因为window还没有在屏幕上实现(附加到native peer),所以repaint没有东西可以画...

第二...

Toolkit.getDefaultToolkit().getImage(rl.getClass().getResource("images/" + fileName));

将图像的实际加载传递给后台线程,这意味着当您获得非空值时 returned,实际图像数据可能尚未完全加载。

您应该考虑使用 ImageIO.read,它只会在图像数据完全加载后 return,并且如果出现问题也会抛出异常(与 Toolkit.getImage 不同) .有关详细信息,请参阅 Reading/Loading an Image...

第三...

所有 Swing 组件都实现了 ImageObserver 接口,这意味着当您调用 Graphics#drawImage 时,您应该将对象作为 ImageObserver 参数传递

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

这允许组件监视图像加载的更新并根据需要重新安排重绘。

第四...

你应该避免覆盖paint顶层容器,除了没有双缓冲,框架和用户之间有一堆组件,这会干扰绘画过程。

相反,您应该从 JPanel 之类的东西扩展并覆盖它的 paintComponent 方法,在那里执行您的自定义绘画。然后,您应该将此面板添加到 JFrame 的实例(或根据需要添加到其他组件)

查看 Painting in AWT and Swing and Performing Custom Painting 了解更多详情

第五...

您应该确保仅在事件调度线程的上下文中创建和修改 UI,有关详细信息,请参阅 Initial Threads

初始化代码时立即调用Paint。要看到这一点,请在构造函数中删除 repaint();,并在 paint 方法中添加 g.drawLine(0, 0, 300, 300);

试试这个,您可能需要添加一些导入:

import javax.swing.*; import java.awt.*;

class MyMainWindow extends JFrame{
    Image img;

    public MyMainWindow(){
        setSize(300,300);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        img = MyResourceLoader.getImage("res.jpg");
        setVisible(true);
    }

    @Override
    public void paint (Graphics g){
        super.paint(g);
        if (img != null)
            g.drawImage(img, 0,0, this);
    } 
}

public class ResourcesProgram {
    public static void main(String[] args) {
        new MyMainWindow();
    } 
}

资源加载器:

import javax.swing.*; import java.awt.*;

public class MyResourceLoader {
    public static Image getImage(String fileName){
        ImageIcon icon = new ImageIcon(getClass().getResource(fileName));
        return icon.getImage();
    }
}