添加 DrawPanel 实例和空指针异常时覆盖整个 GUI

Entire GUI covered when adding instance of DrawPanel and null pointer exception

当我尝试在其构造函数中将实例 "panel" 添加到我的 JFrame 时,出现空指针异常。然而,真正的问题是,如果不向 JFrame 添加 "panel",我的 borderlayout 北布局工作正常,在我添加它之后,应用程序全是白色,除非您滚动北面板中的不同按钮。我想知道如何摆脱空指针异常以及如何使我的 DrawPanel 适合我的 JFrame 边框布局的中心。我有下面的全部代码。

package doStuff;
import java.awt.BorderLayout;
import java.awt.*;
import javax.swing.Timer;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.security.SecureRandom;
import javax.swing.JLabel;
import javax.swing.JFrame;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.*;
import java.awt.Point;
import java.awt.Graphics;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import javax.swing.JPanel;



class DrawPanel extends JPanel
{
    private MyShape[] shapes;//stores all shapes the user draws
    private int shapeCount;//counts number of shapes in array
    private int shapeType;//determines type of shape to draw
    private MyShape currentShape;//represents current shape user is drawing
    private Color currentColor;//represents current drawing color
    private boolean filledShape;//determines whether to draw a filled shape
    private JLabel statusLabel;//status bar that displays coordinates of mouse position

    public DrawPanel(JLabel statusLabel)
    {
        this.statusLabel=statusLabel;
        shapes=new MyShape[100];
        shapeCount=0;
        shapeType=1;
        currentShape=null;
        currentColor=Color.BLACK;
        //setBackground(Color.GREEN);
        setBackground(Color.WHITE);
        addMouseListener(new MouseEventHandler());

    }


    public void setshapeType(int shape)
    {
        this.shapeType=shape;
    }
    public void setcurrentColor(Color color)
    {
        this.currentColor=color;
    }
    public void setfilledShape(boolean filledShape)
    {
        this.filledShape=filledShape;
    }
    public void clearLastShape()
    {
        if (shapeCount==0)
            shapeCount=0;
        else
            shapeCount--;
        repaint();
    }
    public void clearDrawing()
    {
        shapeCount=0;
        repaint();
    }
    private class MouseEventHandler extends MouseAdapter implements MouseMotionListener
    {
        @Override
        public void mousePressed(MouseEvent event)
        {

            if(shapeType==1)
            {
                currentShape=new MyLine();
            }
            if(shapeType==2)
            {
                currentShape = new MyRect();
            }
            else
            {
                currentShape = new MyOval();
            }
            currentShape.setx1(event.getPoint().x);
            currentShape.sety1(event.getPoint().y);
        }
        @Override
        public void mouseReleased(MouseEvent event)
        {
            currentShape.setx2(event.getPoint().x);
            currentShape.sety2(event.getPoint().y);
            shapes[shapeCount-1]=currentShape;
            currentShape=null;
            repaint();
        }
        @Override
        public void mouseMoved(MouseEvent event)
        {
            statusLabel.setText("("+event.getPoint().x+","+event.getPoint().y+")");
        }
        @Override
        public void mouseDragged(MouseEvent event)
        {
            currentShape.setx2(event.getPoint().x);
            currentShape.sety2(event.getPoint().y);
            repaint();
            statusLabel.setText("("+event.getPoint().x+","+event.getPoint().y+")");
        }

    }


    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        for(MyShape shape: shapes)
            shape.draw(g);
    }

}
class DrawFrame extends JFrame
    {
        private static final String[] colorNames = {"Black", "Blue", "Cyan", "Dark Gray", "Gray", "Green", "Light Gray",
        "Magenta", "Orange", "Pink", "Red", "White", "Yellow"};
        private static final Color[] colors = {Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY,
        Color.GRAY, Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED,
        Color.WHITE, Color.YELLOW};
        private static final String[] shapeNames = {"Line", "Rectangle", "Oval"};
        private static final int[] shapes = {1,2,3};
        private final JButton undoButton;
        private final BorderLayout layout;
        private final JButton clearButton;
        private final JComboBox<String> colorsJComboBox;
        private final JComboBox<String> shapesJComboBox;
        private final JCheckBox fillCheckBox;
        private JLabel statusLabel= new JLabel();
        DrawPanel panel = new DrawPanel(statusLabel);
        public DrawFrame()
        {
            super("Java Drawings");
            //setLayout(new BorderLayout())
            layout= new BorderLayout(5,5);
            setLayout(layout);
            colorsJComboBox = new JComboBox<String>(colorNames);
            colorsJComboBox.setMaximumRowCount(4);
            shapesJComboBox = new JComboBox<String>(shapeNames);
            shapesJComboBox.setMaximumRowCount(3);
            undoButton = new JButton("Undo");
            clearButton = new JButton("Clear");
            fillCheckBox = new JCheckBox("Filled");
            /*JPanel centerPanel = new JPanel();
            centerPanel.setLayout(new BorderLayout());
            centerPanel.add(panel);
            add(centerPanel, BorderLayout.CENTER);*/
            JPanel northPanel = new JPanel();
            northPanel.setLayout(new FlowLayout());
            northPanel.add(undoButton);
            northPanel.add(clearButton);
            northPanel.add(colorsJComboBox);
            northPanel.add(shapesJComboBox);
            northPanel.add(fillCheckBox);
            add(northPanel, BorderLayout.NORTH);
            JPanel bottomPanel= new JPanel();
            bottomPanel.setLayout(new FlowLayout());
            bottomPanel.add(statusLabel);
            add(bottomPanel, BorderLayout.SOUTH);
            add(panel, BorderLayout.CENTER);//problem here
            //Event Handlers
            CheckBoxHandler checkBoxHandler = new CheckBoxHandler();
            fillCheckBox.addItemListener(checkBoxHandler);
            undoButton.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent event)
                {
                    panel.clearLastShape();
                }
            });
            clearButton.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent event)
                {
                    panel.clearDrawing();
                }
            });

            colorsJComboBox.addItemListener(new ItemListener()
            {
                    @Override
                    public void itemStateChanged(ItemEvent event)
                    {
                        if(event.getStateChange() == ItemEvent.SELECTED)
                            panel.setcurrentColor(colors[colorsJComboBox.getSelectedIndex()]);
                    }
            }
            );
            shapesJComboBox.addItemListener(new ItemListener()
            {
                    @Override
                    public void itemStateChanged(ItemEvent event)
                    {
                        if(event.getStateChange() == ItemEvent.SELECTED)
                            panel.setshapeType(shapes[shapesJComboBox.getSelectedIndex()]);
                    }
            }
            );
        }
        private class CheckBoxHandler implements ItemListener
        {
            @Override
            public void itemStateChanged(ItemEvent event)
            {
                if(fillCheckBox.isSelected())
                    panel.setfilledShape(true);
            }
        }
    }
abstract class MyShape
{
    private int x1;
    private int y1;
    private int x2;
    private int y2;
    private Color color;

    public MyShape()
    {
          this.x1=this.x2=this.y1=this.y2=0;
          this.color=Color.BLACK;
    }
    public MyShape(int x1, int y1, int x2, int y2, Color color)
    {
        this.x1=x1;
        this.x2=x2;
        this.y1=y1;
        this.y2=y2;
        this.color=color;
    }
    public void setx1(int x1)
    {
        this.x1=x1;
    }
    public void setx2(int x2)
    {
        this.x2=x2;
    }
    public void sety1(int y1)
    {
        this.y1=y1;
    }
    public void sety2(int y2)
    {
        this.y2=y2;
    }
    public void setColor(Color color)
    {
        this.color=color;
    }
    public Color getColor()
    {
        return color;
    }
    public int getx1()
    {
        return x1;
    }
    public int getx2()
    {
        return x2;
    }
    public int gety2()
    {
        return y2;
    }
    public int gety1()
    {
        return y1;
    }
    public int getUpperLeftx()
    {
        if (x1<=x2)
            return x1;
        else
            return x2;
    }
    public int getUpperLefty()
    {
        if (y1<=y2)
            return y1;
        else
            return y2;
    }
    public int getHeight()
    {
        return(Math.abs(y1-y2));
    }
    public int getWidth()
    {
        return(Math.abs(x1-x2));
    }
    public void draw(Graphics g)
    {
    }
}
abstract class MyBoundedShape extends MyShape
{
    private boolean fillyn;
    MyBoundedShape()
    {
        super();
        fillyn=false;
    }
    MyBoundedShape(int x1,int y1,int x2,int y2,Color color, boolean fillyn)
    {
        super(x1,y1,x2,y2,color);
        this.fillyn=fillyn;
    }
    public void setfillyn(boolean fillyn)
    {
        this.fillyn=fillyn;
    }
    public boolean getfillyn()
    {
        return fillyn;
    }
    @Override
    public void draw(Graphics g)
    {

    }

}

class MyLine extends MyShape
{
    MyLine()
    {
        super();
    }

    MyLine(int x1, int y1, int x2, int y2, Color color)
    {
        super(x1,y1,x2,y2,color);
    }
    @Override
    public void draw(Graphics g)
    {
        g.setColor(super.getColor());
        g.drawLine(getx1(), gety1(), getx2(), gety2());
    }
}

class MyRect extends MyBoundedShape
{
    MyRect()
    {
        super();
    }

    MyRect(int x1, int y1, int x2, int y2, Color color, boolean fillyn)
    {
        super(x1,y1,x2,y2,color,fillyn);
    }


    @Override
    public void draw(Graphics g)
    {
        g.setColor(getColor());
        if(super.getfillyn())
            g.fillRect(getx1(), gety1(), getx2(), gety2());
        else
            g.drawRect(getx1(), gety1(), getx2(), gety2());
    }
}
class MyOval extends MyBoundedShape
{
    MyOval()
    {
        super();
    }

    MyOval(int x1, int y1, int x2, int y2, Color color, boolean fillyn)
    {
       super(x1,y1,x2,y2,color,fillyn);
    }
    @Override
    public void draw(Graphics g)
    {
        g.setColor(super.getColor());
        if(getfillyn())
        g.fillOval(getx1(), gety1(), getx2(), gety2());
        else
        g.drawOval(getx1(), gety1(), getx2(),gety2());
    }
}




public class doStuff {


    public static void main(String[] args) 
    {
       /* DrawPanel panel = new DrawPanel();
        JFrame app = new JFrame();
        JLabel statusLabel = new JLabel(panel.getNumStatus());


        app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        app.add(panel);
        app.add(statusLabel, BorderLayout.SOUTH);
        app.setSize(300,300);
        app.setVisible(true);*/
        DrawFrame drawFrame = new DrawFrame();
        drawFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        drawFrame.setSize(600,600);
        drawFrame.setVisible(true);

    }

}

这是我的固定代码:我必须更改我的 clearDrawing 和 clearLastShape 方法以适应从数组到列表的更改,以及我的 paintComponent 方法以在我拖动鼠标时正确显示。我知道有几个多余的进口。感谢您的帮助!

package doStuff;
import java.awt.BorderLayout;
import java.awt.*;
import java.util.List;
import java.util.LinkedList;
import java.util.ListIterator;
import javax.swing.Timer;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.security.SecureRandom;
import javax.swing.JLabel;
import javax.swing.JFrame;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.*;
import java.awt.Point;
import java.awt.Graphics;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.JPanel;



class DrawPanel extends JPanel
{
    private List<MyShape> shapes;
    private int shapeType;//determines type of shape to draw
    private MyShape currentShape;//represents current shape user is drawing
    private Color currentColor;//represents current drawing color
    private boolean filledShape;//determines whether to draw a filled shape
    private JLabel statusLabel;//status bar that displays coordinates of mouse position
    public DrawPanel(JLabel statusLabel)
    {
        this.statusLabel=statusLabel;
        shapes = new ArrayList<>(100);
        shapeType=1;
        currentShape=null;
        currentColor=Color.BLACK;
        setBackground(Color.WHITE);
        MouseEventHandler handler = new MouseEventHandler();
        addMouseListener(handler);
        addMouseMotionListener(handler);
    }
    
    
    public void setshapeType(int shape)
    {
        this.shapeType=shape;
    }
    public void setcurrentColor(Color color)
    {
        this.currentColor=color;
    }
    public void setfilledShape(boolean filledShape)
    {
        this.filledShape=filledShape;
    }
    public void clearLastShape()
    {
        if (shapes.size()<=1)
            shapes.removeAll(shapes);
        else
            shapes.remove(1);
        repaint();
    }
    public void clearDrawing()
    {
        shapes.removeAll(shapes);
        repaint();
    }
    private class MouseEventHandler extends MouseAdapter implements MouseMotionListener
    {
        @Override
        public void mousePressed(MouseEvent event)
        {
            if(shapeType==1)
            {
                currentShape=new MyLine(event.getX(),event.getY(),0,0,currentColor);
            }
            else if(shapeType==2)
            {
                currentShape= new MyRect(event.getX(),event.getY(),0,0,currentColor,filledShape);
            }
            else
            {
                currentShape= new MyOval(event.getX(),event.getY(),0,0,currentColor,filledShape);
            }
        }
        @Override
        public void mouseReleased(MouseEvent event)
        {
            
            currentShape.setx2(event.getX());
            currentShape.sety2(event.getY());
            shapes.add(currentShape);
            currentShape=null;
            repaint();
        }
        @Override
        public void mouseMoved(MouseEvent event)
        {
            statusLabel.setText("("+event.getX()+","+event.getY()+")");
        }
        @Override
        public void mouseDragged(MouseEvent event)
        {
            currentShape.setx2(event.getX());
            currentShape.sety2(event.getY());
            repaint();
            statusLabel.setText("("+event.getX()+","+event.getY()+")");
        }
        
    }
    
    
    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        if(currentShape!=null)
        {
            currentShape.draw(g);
            for(MyShape shape:shapes)
                {
                    shape.draw(g);
                }
        }
        else{
        for(MyShape shape:shapes)
        {
            shape.draw(g);
        }
                }
    }
    
}
class DrawFrame extends JFrame
    {
        private static final String[] colorNames = {"Black", "Blue", "Cyan", "Dark Gray", "Gray", "Green", "Light Gray",
        "Magenta", "Orange", "Pink", "Red", "White", "Yellow"};
        private static final Color[] colors = {Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY,
        Color.GRAY, Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED,
        Color.WHITE, Color.YELLOW};
        private static final String[] shapeNames = {"Line", "Rectangle", "Oval"};
        private static final int[] shapes = {1,2,3};
        private final JButton undoButton;
        private final BorderLayout layout;
        private final JButton clearButton;
        private final JComboBox<String> colorsJComboBox;
        private final JComboBox<String> shapesJComboBox;
        private final JCheckBox fillCheckBox;
        private JLabel statusLabel= new JLabel();
        DrawPanel panel = new DrawPanel(statusLabel);
        public DrawFrame()
        {
            super("Java Drawings");
            //setLayout(new BorderLayout())
            layout= new BorderLayout(5,5);
            setLayout(layout);
            colorsJComboBox = new JComboBox<String>(colorNames);
            colorsJComboBox.setMaximumRowCount(4);
            shapesJComboBox = new JComboBox<String>(shapeNames);
            shapesJComboBox.setMaximumRowCount(3);
            undoButton = new JButton("Undo");
            clearButton = new JButton("Clear");
            fillCheckBox = new JCheckBox("Filled");
            JPanel northPanel = new JPanel();
            northPanel.setLayout(new FlowLayout());
            northPanel.add(undoButton);
            northPanel.add(clearButton);
            northPanel.add(colorsJComboBox);
            northPanel.add(shapesJComboBox);
            northPanel.add(fillCheckBox);
            add(northPanel, BorderLayout.NORTH);
            JPanel bottomPanel= new JPanel();
            bottomPanel.setLayout(new FlowLayout());
            bottomPanel.add(statusLabel);
            add(bottomPanel, BorderLayout.SOUTH);
            add(panel, BorderLayout.CENTER);
            //Event Handlers
            CheckBoxHandler checkBoxHandler = new CheckBoxHandler();
            fillCheckBox.addItemListener(checkBoxHandler);
            undoButton.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent event)
                {
                    panel.clearLastShape();
                }
            });
            clearButton.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent event)
                {
                    panel.clearDrawing();
                }
            });
            
            colorsJComboBox.addItemListener(new ItemListener()
            {
                    @Override
                    public void itemStateChanged(ItemEvent event)
                    {
                        if(event.getStateChange() == ItemEvent.SELECTED)
                            panel.setcurrentColor(colors[colorsJComboBox.getSelectedIndex()]);
                    }
            }
            );
            shapesJComboBox.addItemListener(new ItemListener()
            {
                    @Override
                    public void itemStateChanged(ItemEvent event)
                    {
                        if(event.getStateChange() == ItemEvent.SELECTED)
                            panel.setshapeType(shapes[shapesJComboBox.getSelectedIndex()]);
                    }
            }
            );
        }
        private class CheckBoxHandler implements ItemListener
        {
            @Override
            public void itemStateChanged(ItemEvent event)
            {
                if(fillCheckBox.isSelected())
                    panel.setfilledShape(true);
            }
        }
    }
abstract class MyShape
{
    private int x1;
    private int y1;
    private int x2;
    private int y2;
    private Color color;
    
    public MyShape()
    {
          this.x1=this.x2=this.y1=this.y2=0;
          this.color=Color.BLACK;
    }
    public MyShape(int x1, int y1, int x2, int y2, Color color)
    {
        this.x1=x1;
        this.x2=x2;
        this.y1=y1;
        this.y2=y2;
        this.color=color;
    }
    public void setx1(int x1)
    {
        this.x1=x1;
    }
    public void setx2(int x2)
    {
        this.x2=x2;
    }
    public void sety1(int y1)
    {
        this.y1=y1;
    }
    public void sety2(int y2)
    {
        this.y2=y2;
    }
    public void setColor(Color color)
    {
        this.color=color;
    }
    public Color getColor()
    {
        return color;
    }
    public int getx1()
    {
        return x1;
    }
    public int getx2()
    {
        return x2;
    }
    public int gety2()
    {
        return y2;
    }
    public int gety1()
    {
        return y1;
    }
    public int getUpperLeftx()
    {
        if (x1<=x2)
            return x1;
        else
            return x2;
    }
    public int getUpperLefty()
    {
        if (y1<=y2)
            return y1;
        else
            return y2;
    }
    public int getHeight()
    {
        return(Math.abs(y1-y2));
    }
    public int getWidth()
    {
        return(Math.abs(x1-x2));
    }
    public void draw(Graphics g)
    {
    }
}
abstract class MyBoundedShape extends MyShape
{
    private boolean fillyn;
    MyBoundedShape()
    {
        super();
        fillyn=false;
    }
    MyBoundedShape(int x1,int y1,int x2,int y2,Color color, boolean fillyn)
    {
        super(x1,y1,x2,y2,color);
        this.fillyn=fillyn;
    }
    public void setfillyn(boolean fillyn)
    {
        this.fillyn=fillyn;
    }
    public boolean getfillyn()
    {
        return fillyn;
    }
    @Override
    public void draw(Graphics g)
    {
        
    }
    
}

class MyLine extends MyShape
{
    MyLine()
    {
        super();
    }
    
    MyLine(int x1, int y1, int x2, int y2, Color color)
    {
        super(x1,y1,x2,y2,color);
    }
    @Override
    public void draw(Graphics g)
    {
        g.setColor(super.getColor());
        g.drawLine(getx1(), gety1(), getx2(), gety2());
    }
}

class MyRect extends MyBoundedShape
{
    MyRect()
    {
        super();
    }
    
    MyRect(int x1, int y1, int x2, int y2, Color color, boolean fillyn)
    {
        super(x1,y1,x2,y2,color,fillyn);
    }
    
    
    @Override
    public void draw(Graphics g)
    {
        
        
        int x = Math.min(getx1(), getx2());
        int y = Math.min(gety1(), gety2());
        int w = Math.abs(getx1() - getx2());
        int h = Math.abs(gety1() - gety2());
        
        g.setColor(getColor());
        if(super.getfillyn())
            g.fillRect(x,y,w,h);
        else
            g.drawRect(x,y,w,h);
    }
}
class MyOval extends MyBoundedShape
{
    MyOval()
    {
        super();
    }
    
    MyOval(int x1, int y1, int x2, int y2, Color color, boolean fillyn)
    {
       super(x1,y1,x2,y2,color,fillyn);
    }
    @Override
    public void draw(Graphics g)
    {
        int x = Math.min(getx1(), getx2());
        int y = Math.min(gety1(), gety2());
        int w = Math.abs(getx1() - getx2());
        int h = Math.abs(gety1() - gety2());
        
        g.setColor(getColor());
        if(super.getfillyn())
            g.fillOval(x,y,w,h);
        else
            g.drawOval(x,y,w,h);
    }
}




public class doStuff {

    
    public static void main(String[] args) 
    {
        DrawFrame drawFrame = new DrawFrame();
        drawFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        drawFrame.setSize(600,600);
        drawFrame.setVisible(true);
        
    }
    
}

您的 NullPointerException 是由

引起的
shapes = new MyShape[100];

您创建了一个 MyShape 类型的数组,但从未向其中添加任何内容,因此它充满了 null

考虑将其更改为使用某种 List

class DrawPanel extends JPanel {

    private List<MyShape> shapes;//stores all shapes the user draws
    //...

    public DrawPanel(JLabel statusLabel) {
        //...
        shapes = new ArrayList<>(100);

一旦您更正了 NullPointExceptionDrawPanel 应该就没问题了。