Java图形上的NullPointerException

Java图形上的NullPointerException,java,swing,awt,Java,Swing,Awt,我正在尝试实现一种方法来绘制网格的特定部分。为此,我重写了paintComponent方法: public class Frame extends JPanel { ... @Override public void paintComponent( Graphics g ) { super.paintComponent( g ); g.clearRect(0, 0, getWidth(), getHeight()); this.rectWidth = getWidth

我正在尝试实现一种方法来绘制网格的特定部分。为此,我重写了paintComponent方法:

public class Frame extends JPanel {
...
@Override
public void paintComponent( Graphics g ) {

    super.paintComponent( g );

    g.clearRect(0, 0, getWidth(), getHeight());
    this.rectWidth = getWidth() / this.NUM_COLUMNS;
    this.rectHeight = getHeight() / this.NUM_ROWS;

    for (int i = 0; i < NUM_ROWS; i++) {

        for (int j = 0; j < NUM_COLUMNS; j++) {

            int x = i * this.rectWidth;
            int y = j * this.rectHeight;
            g.setColor( Color.WHITE );
            g.fillRect( x, y, this.rectWidth, this.rectHeight );

        }
    }

}
}
电话应该是这样的

// TESTING
    this.modelMap.specificPaint( 40,40,Color.RED );
    this.modelMap.specificPaint( 10,10,Color.RED );
    this.modelMap.specificPaint( 20,25,Color.BLUE );
图形对象出现空指针错误,为什么不能恢复并使用它


有更好的方法吗?

从组件获取图形对象时千万不要这样做:

Graphics g = this.getGraphics();
这样获得的图形对象不会长期存在,这可能会导致NPE(就像您得到的一样)或图像在重新绘制时无法持久。相反,请在paintComponent方法中进行绘图。请注意,您可以调用
repaint(…)
并通过传入矩形参数指定要绘制的特定矩形

请注意,如果要进行不移动的点绘制,可以对BuffereImage调用
getGraphics()
,然后在paintComponent方法中绘制BuffereImage

一个不相关的建议:避免调用类
Frame
,因为如果不小心,这可能会导致与
java.awt.Frame
类的名称冲突

例如:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.*;

@SuppressWarnings("serial")
public class MyPanel extends JPanel {
    private static final int PREF_W = 400;
    private static final int PREF_H = PREF_W;
    private int cols;
    private int rows;
    private static final Color BG = Color.BLACK;
    private static final int GAP = 1;
    private BufferedImage img;
    private int rectWidth;
    private int rectHeight;

    public MyPanel(int rows, int cols) {
        this.cols = cols;
        this.rows = rows;
        img = createMyImage();
    }

    public void specificPaint(int coordinateX, int coordinateY, Color color) {
        Graphics g = img.getGraphics(); // get img's Graphics object
        int x = coordinateX * this.rectWidth + GAP;
        int y = coordinateY * this.rectHeight + GAP;
        g.setColor(color);
        g.fillRect(x, y, rectWidth - 2 * GAP, rectWidth - 2 * GAP);
        g.dispose();
        repaint();
    }

    private BufferedImage createMyImage() {
        img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        g2.setBackground(BG);
        g2.clearRect(0, 0, img.getWidth(), img.getHeight());
        this.rectWidth = img.getWidth() / cols;
        this.rectHeight = img.getHeight() / rows;

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                int x = i * this.rectWidth + GAP;
                int y = j * this.rectHeight + GAP;
                g2.setColor(Color.WHITE);
                g2.fillRect(x, y, this.rectWidth - 2 * GAP, this.rectHeight - 2 * GAP);
            }
        }
        g2.dispose();
        return img;
    }

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

        // if you need to draw changing non-static images, do it here
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet() || img == null) {
            return super.getPreferredSize();
        }
        int w = img.getWidth();
        int h = img.getHeight();
        return new Dimension(w, h);
    }

    private static void createAndShowGui() {
        MyPanel modelMap = new MyPanel(50, 50);
        JFrame frame = new JFrame("MyPanel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(modelMap);
        frame.pack();
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        modelMap.specificPaint( 40,40,Color.RED );
        modelMap.specificPaint( 10,10,Color.RED );
        modelMap.specificPaint( 20,25,Color.BLUE );
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.image.buffereImage;
导入javax.swing.*;
@抑制警告(“串行”)
公共类MyPanel扩展了JPanel{
专用静态最终整型预加值W=400;
私有静态final int PREF_H=PREF_W;
私人公司;
私有int行;
专用静态最终颜色BG=Color.BLACK;
专用静态最终内部间隙=1;
专用缓冲图像img;
私有宽度;
私家车高度;
公共MyPanel(整数行、整数列){
this.cols=cols;
this.rows=行;
img=createMyImage();
}
公共空间专用油漆(内部坐标、内部坐标、颜色){
Graphics g=img.getGraphics();//获取img的图形对象
int x=坐标x*this.rectWidth+间隙;
int y=坐标y*this.rect高度+间隙;
g、 设置颜色(颜色);
g、 fillRect(x,y,rectWidth-2*间隙,rectWidth-2*间隙);
g、 处置();
重新油漆();
}
私有缓冲区映像createMyImage(){
img=新的BuffereImage(PREF_W、PREF_H、BuffereImage.TYPE_INT_ARGB);
Graphics2D g2=img.createGraphics();
g2.挫折背景(BG);
g2.clearRect(0,0,img.getWidth(),img.getHeight());
this.rectWidth=img.getWidth()/cols;
this.rectHeight=img.getHeight()/行;
对于(int i=0;i
从组件获取图形对象时,切勿执行此操作:

Graphics g = this.getGraphics();
这样获得的图形对象不会长期存在,这可能会导致NPE(就像您得到的一样)或图像在重新绘制时无法持久。相反,请在paintComponent方法中进行绘图。请注意,您可以调用
repaint(…)
并通过传入矩形参数指定要绘制的特定矩形

请注意,如果要进行不移动的点绘制,可以对BuffereImage调用
getGraphics()
,然后在paintComponent方法中绘制BuffereImage

一个不相关的建议:避免调用类
Frame
,因为如果不小心,这可能会导致与
java.awt.Frame
类的名称冲突

例如:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.*;

@SuppressWarnings("serial")
public class MyPanel extends JPanel {
    private static final int PREF_W = 400;
    private static final int PREF_H = PREF_W;
    private int cols;
    private int rows;
    private static final Color BG = Color.BLACK;
    private static final int GAP = 1;
    private BufferedImage img;
    private int rectWidth;
    private int rectHeight;

    public MyPanel(int rows, int cols) {
        this.cols = cols;
        this.rows = rows;
        img = createMyImage();
    }

    public void specificPaint(int coordinateX, int coordinateY, Color color) {
        Graphics g = img.getGraphics(); // get img's Graphics object
        int x = coordinateX * this.rectWidth + GAP;
        int y = coordinateY * this.rectHeight + GAP;
        g.setColor(color);
        g.fillRect(x, y, rectWidth - 2 * GAP, rectWidth - 2 * GAP);
        g.dispose();
        repaint();
    }

    private BufferedImage createMyImage() {
        img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        g2.setBackground(BG);
        g2.clearRect(0, 0, img.getWidth(), img.getHeight());
        this.rectWidth = img.getWidth() / cols;
        this.rectHeight = img.getHeight() / rows;

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                int x = i * this.rectWidth + GAP;
                int y = j * this.rectHeight + GAP;
                g2.setColor(Color.WHITE);
                g2.fillRect(x, y, this.rectWidth - 2 * GAP, this.rectHeight - 2 * GAP);
            }
        }
        g2.dispose();
        return img;
    }

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

        // if you need to draw changing non-static images, do it here
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet() || img == null) {
            return super.getPreferredSize();
        }
        int w = img.getWidth();
        int h = img.getHeight();
        return new Dimension(w, h);
    }

    private static void createAndShowGui() {
        MyPanel modelMap = new MyPanel(50, 50);
        JFrame frame = new JFrame("MyPanel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(modelMap);
        frame.pack();
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        modelMap.specificPaint( 40,40,Color.RED );
        modelMap.specificPaint( 10,10,Color.RED );
        modelMap.specificPaint( 20,25,Color.BLUE );
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.image.buffereImage;
导入javax.swing.*;
@抑制警告(“串行”)
公共类MyPanel扩展了JPanel{
专用静态最终整型预加值W=400;
私有静态final int PREF_H=PREF_W;
私人公司;
私有int行;
专用静态最终颜色BG=Color.BLACK;
专用静态最终内部间隙=1;
专用缓冲图像img;
私有宽度;
私家车高度;
公共MyPanel(整数行、整数列){
this.cols=cols;
this.rows=行;
img=createMyImage();
}
公共空间专用油漆(内部坐标、内部坐标、颜色){
Graphics g=img.getGraphics();//获取img的图形对象
int x=坐标x*this.rectWidth+间隙;
int y=坐标y*this.rect高度+间隙;
public void specificPaint(int coordinateX, int coordinateY, Color color, Graphics g)