JFrame图形会忽略前几个渲染

问题描述

下面是查看该错误的最少代码

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

public class Main1 extends JFrame {
    static Main1 main;
    public Main1() {
        super("app");
    }

    public static void main(String[] args) {
        main = new Main1();
        main.setBounds(300,300,800,500);
        main.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
        main.setVisible(true);
        Graphics g = main.getGraphics();
        for(int i = 0; i < 100; i++){
            g.setColor(new Color(255,0));
            g.fillRect(0,500);
        }
    }
}

如果我在“ for”循环中使用100,则该框架似乎没有着色,但是200个循环就足以对其着色。

我想创建一个框架很少变化的应用程序,但是此功能破坏了代码的质量,因为我必须制作许多虚拟框架。

解决方法

public static void main(String[] args) {
    main = new Main1();
    main.setBounds(300,300,800,500);
    main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    main.setVisible(true);
    Graphics g = main.getGraphics();
    for(int i = 0; i < 100; i++){
        g.setColor(new Color(255,0));
        g.fillRect(0,500);
    }
}

这不是您执行Swing图形的方式。通过在组件上调用.getGraphics()来获取Graphics对象,将为您提供短暂的不稳定对象,有时甚至为null。例如,创建的JFrame渲染需要花费一些时间,如果您调用getGraphics()并尝试在渲染之前使用它,则该对象可能为null,并且肯定不会运行。

使用JVM提供的Graphics对象,按照教程中的说明在JPanel的paintComponent方法中进行绘画:

public class MainPanel extends JPanel {

    public MainPanel {
        setPreferredSize(new Dimension(800,500)));
        setBackground(new Color(255,0)); // if you just want to set background
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        
        // use g here do do your drawing
    }

}

然后像这样使用它:

public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {
        JFrame frame = new JFrame("GUI");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new MainPanel());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    });
}  

教程:Lesson: Performing Custom Painting

是的,如果您想驱动一个简单的动画,请使用Swing Timer来帮助驱动它,如下所示:

public class MainPanel extends JPanel {
    private int x = 0;
    private int y = 0;

    public MainPanel {
        setPreferredSize(new Dimension(800,0)); // if you just want to set background
        
        // timer code:
        int timerDelay = 15;
        new Timer(timerDelay,()-> {
            x += 4;
            y += 4;
            repaint();
        }).start();
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        
        // use g here do do your drawing
        g.setColor(Color.BLUE);
        g.drawRect(x,y,20,20);
    }

}