为什么我得到这个NullPointerException?

时间:2012-01-26 05:01:48

标签: java swing graphics canvas nullpointerexception

我无法弄清楚这一点。使用新的Canvas()初始化Canvas后,引用它会导致NullPointerException。文档告诉我,当Canvas没有“启用”时会发生这种情况,但我不知道启用它意味着什么。我尝试通过包含while(!cvs.isEnabled())来调试它;但该计划刚挂了。可能导致Canvas未启用的条件是什么,以及如何修复它们?

Exception in thread "main" java.lang.NullPointerException
    at matt.io.ConsoleCanvas.<init>(ConsoleCanvas.java:72)
    at matt.io.ConsoleCanvas.<init>(ConsoleCanvas.java:51)
    at matt.io.ConsoleCanvas.main(ConsoleCanvas.java:32)

public class ConsoleCanvas extends JFrame
{
    private static final Font DEFAULT_FONT = new Font("Monospaced", Font.PLAIN, 12);
    public static void main(String[] args)
    {
        ConsoleCanvas me = new ConsoleCanvas(); //ConsoleCanvas.java:32
        //Program has crashed by this point, so rest of main removed to be concise
    }

    protected JTextField in;
    private Canvas cvs;
    private int row;
    private int col;

    public ConsoleCanvas()
    {
        this("Console Pane", 80, 10); //ConsoleCanvas.java:51
    }

    public ConsoleCanvas(String title, int rows, int cols)
    {
        in = new JTextField();
        in.setEditable(true);
        in.setFont(DEFAULT_FONT);
        in.setColumns(cols);

        cvs = new Canvas();
        cvs.setSize(in.getWidth(), in.getHeight() * rows);
        cvs.setFont(DEFAULT_FONT);
        row = 0;
        col = cvs.getGraphics().getFontMetrics().getHeight(); //ConsoleCanvas.java:72
        //Program crashes at this line, so I'll leave out the rest for brevity again
        //I've isolated the null to the Graphics returned by cvs.getGraphics()
    }
}

5 个答案:

答案 0 :(得分:4)

我没有使用swing很长一段时间,但是在调用get图形之前尝试将画布添加到Panel(面板也应该有某种形式的布局)。 你可以在这里找到一个有趣的教程:http://docs.oracle.com/javase/tutorial/uiswing/ “要在屏幕上显示,每个GUI组件都必须是包含层次结构的一部分。包含层次结构是一个以顶层容器为根的组件树。我们将向您展示一个。”所以我认为实例化canvas类是不够的。只有在将图形对象添加到顶级容器后才会将其分配给画布对象。

答案 1 :(得分:2)

在组件可显示之前,其图形将为null。这是一个真正的麻烦,因为没有FontMetrics没有简单的方法来访问Graphics

我知道有几种解决方案:

如果您只想要行高,Font.getLineMetrics()就足够了。

Toolkit.getDefaultToolkit().getFontMetrics(Font)有效,但已被弃用。

一个不弃用但不必要的迂回解决方案是创建BufferedImage并获取其Graphics

修改

实际上,从1.5开始,您可以cvs.getFontMetrics(DEFAULT_FONT)。我不敢相信我以前从未注意到这一点!

答案 2 :(得分:1)

您可能首先不应该使用Canvas。这是一个古老的AWT课程。如果您正在使用JFrame,那么您正在使用Swing。如果你想绘制一些东西:子类JComponent,覆盖paintComponent,你可以把你的绘图代码放在那里。我的猜测是getGraphics()返回null,因为它没有附加到父级。您可能需要等到稍后才能访问Graphics对象,就像显示它一样。

答案 3 :(得分:0)

你不应该首先将Canvas添加到JFrame吗?

cvs = new Canvas(); 
getContentPane().add(cvs); 

答案 4 :(得分:0)

someObject.getGraphics()在构造函数中是非常冒险的。在这种情况下,可能因为尚未显示。我建议在col上使用lazy instantiation。只需编写一个getter来检查它是否已被分配:

public Graphics getCol() {
    if (col == null) {
        col = cvs.getGraphics();
    }
    return col;
}  

这样,你应该在第一次需要时获取Graphics对象。作为一个额外的安全措施,您可以检查分配是否成功,如果它为空(即失败快速),则抛出未经检查的异常。