Search code examples
javaswingerror-handlingnullpaintcomponent

Any solution for a Null Pointer Exception Error resulting from Java paintComponent() referencing a separate class?


I've not been coding for very long, but this is the most peculiar error that I've seen thus far. Now I know that it says Null Pointer Exception error, which this is, but its a specific one that I haven't been able to find on the web for well over a week now, going on two. I've come across a very unique problem and I am in dire need of help. (I've come up with a workaround so I'll finish my project on time, but this error is still bugging me). (Code will be at the very bottom of the question).

The Project: To create a traffic light simulation that:

  • when started is in an "off" and must be turned on with the 'o' key on the keyboard. It must be able to turn off as well.
  • When the "f" key is pressed it causes the yellow light to flash.
  • Must have a real traffic light progression (Green > Yellow > Red > Green > etc.)

The Problem: When the paintComponent(Graphics pen) in my panel method occurs, multiple errors are generated from it. (Screenshot here: Errors)

I've deducted that it occurs sometime after the creation of the object within the panel (makes more sense when you've read the code). It's very peculiar as the workaround simply is a copy and paste from the class methods, directly into the original panel.

i.e. if my code was to draw a Oval with pen.drawOval(insert parameters) it would work in the panel class holding the paintComponent(Graphics pen) method within it. BUT, it would not work if it was in, let's say, a Circle class.

This error is only generated when paintComponent accesses an object from another Class, a variable from another class, or a method from another class.

If a Circle object was used, object.drawOval(parameters) would not work, but if there was another public void method used within the panel, called objectDraw(Graphics pen) and was run from the paintComponent as objectDraw(pen) it would work.

I hope I explained it the best I could.

Now for the code that generates the area.

I have the sickening feeling that's its something so simple that I've overlooked. This is really my last resort as I haven't been able to discover why this would generate the error.

(Can JComponent become corrupted? Could it just be user specific?)

The Code:

Consider Lights as a group class holding multiple objects inside of it as private classes. (Could this be the problem, the private classes?)

            /******************
              * Lights.java
              * 
              * Creates graphic objects.
              * 
              ******************/
            import java.awt.*; //Import the awt package.

            public class Lights{ //Driver class header.

              private final int RED = 1; //Creates switch constant.
              private final int YELLOW = 2; //Creates switch constant.
              private final int GREEN = 3; //Creates switch constant.
              private final int ALL_ON = 5; //Creates switch constant.
              private final int ALL_OFF = 6; //Creates switch constant.
              private final int BACKGROUND = 0; //Background switch constant.
              private final int FOREGROUND = 8; //Foreground switch constant.
              private final int FLASHING_YELLOW = 4; //Creates Flashing Yellow
              private final int DARK_YELLOW = 9; //Case in case.
              private int flashingColor = YELLOW; //Case in case.
              private boolean flashingYellow = false; //Creates false by default flashingYellow boolean.
              private Color lightColor; //Color variable lightcolor.
              private int colorSwitch; //Switch integer using constants and lightcolor.
              private int typeSwitch; //Also similar to above.
              private int x, y, lightswitch; //Other integers.
              private Rectangle grayBG, blackBG;
              private Circle red, green, yellow, redFore, greenFore, yellowFore;


              public Lights(){
                Rectangle grayBG = new Rectangle(35, 35, 280, 830, true);
                Rectangle blackBG = new Rectangle(50, 50, 250, 800, true);
                Circle red = new Circle(80, 75, 200, 200, true);
                Circle green = new Circle(80, 575, 200, 200, true);
                Circle yellow = new Circle(80, 325, 200, 200, true);
                Circle redFore = new Circle(80, 75, 200, 200, false);
                Circle greenFore = new Circle(80, 575, 200, 200, false);
                Circle yellowFore = new Circle(80, 325, 200, 200, false);
              }

              //Drawn when flash is on.
              public void flashOn(Graphics g){
                drawYellowLight(g, true);        
                drawGreenLight(g, false);
                drawRedLight(g, false);
                drawFore(g);
              }

              //Drawn when light is off.
              public void flashOff(Graphics g){
                drawYellowLight(g, false); 
                drawGreenLight(g, false);
                drawRedLight(g, false);
                drawFore(g);  
              }


              //Draws the foreground.
              public void drawFore(Graphics pen){
                drawRed(pen);
                drawYellow(pen);
                drawGreen(pen);
              }

              //Draws the foreground's red, yellow, and green.
              public void drawRed(Graphics pen){    
                pen.setColor(Color.RED);
                redFore.draw(pen);    
              }  
              public void drawYellow(Graphics pen){    
                pen.setColor(Color.YELLOW);
                yellowFore.draw(pen);    
              }  
              public void drawGreen(Graphics pen){    
                pen.setColor(Color.GREEN);
                greenFore.draw(pen);    
              }


              //Draws the background.
              public void drawBox(Graphics pen){
                //HTML Color Code for 'LightYellow4' (looks gray though); Color GRAY = new Color(139, 139, 122);
                pen.setColor(new Color(139, 139, 122));
                grayBG.draw(pen);
                pen.setColor(Color.BLACK);
                blackBG.draw(pen);
              }



              //Draws the green light whether on or off.
              public void drawGreenLight(Graphics pen, boolean isOn){
                //Color darkGreen = new Color(105, 139, 105);
                //Color lightGreen = new Color(0, 238, 0);
                if(!isOn){
                  pen.setColor(new Color(105, 139, 105));
                  green.draw(pen);        
                } else {
                  pen.setColor(new Color(0, 238, 0));
                  green.draw(pen);
                }
              }







              //Draws the yellow light whether on or off.
              public void drawYellowLight(Graphics pen, boolean isOn){     
                //Color darkYellow = new Color(139, 69, 0);
                //Color lightYellow = new Color(255, 215, 0);
                if(!isOn){
                  pen.setColor(new Color(139, 69, 0));
                  yellow.draw(pen);      
                } else {
                  pen.setColor(new Color(255, 215, 0));
                  yellow.draw(pen); 
                } 
              }







              //Draws the red light whether on or off.  
              public void drawRedLight(Graphics pen, boolean isOn){     
                //Color darkRed = new Color(139, 26, 26);
                //Color lightRed = new Color(255, 48, 48);
                if(!isOn){
                  pen.setColor(new Color(139, 26, 26));
                  red.draw(pen);      
                } else {
                  pen.setColor(new Color(255, 48, 48));
                  red.draw(pen); 
                } 
              }



              /******************
                * Lights$Rectangle.java
                * 
                * Creates a graphic object named Rectangle.
                * 
                ******************/
              private class Rectangle{ //Driver class header.

                //Define global private integers.
                private int x, y, h, w;
                private boolean fill;

                //Methods

                //Object constructor, Definition.
                //Defines the info for a rectangle.
                public Rectangle(int a, int b, int height, int width, boolean isFilled){
                  x = a;
                  y = b;
                  h = height;
                  w = width;
                  fill = isFilled;
                }

                public void draw(Graphics pen){
                  if(fill == true){
                    int xPosition = x - w;
                    int yPosition = y - h;
                    pen.fillRect(xPosition, yPosition, w, h);
                  } else {      
                    int xPosition = x - w;
                    int yPosition = y - h;
                    pen.drawRect(xPosition, yPosition, w, h);  
                  }
                }

              }





              /******************
                * Lights$Circle.java
                * 
                * Creates a graphic object named Rectangle.
                * 
                ******************/
              private class Circle{
                //Define global private integers.
                private int x, y, radius;
                private boolean fill;


                //Object constructor, Definition.
                //Defines the info for a circle.
                public Circle(int a, int b, int size, int size_alt, boolean isFilled){
                  x = a;
                  y = b;
                  radius = ((int)size/2);
                  fill = isFilled;

                }

                public void draw(Graphics pen){
                  if(fill == true){
                    int diameter = (radius*2);
                    int xPosition = x - radius;
                    int yPosition = y - radius;
                    pen.fillOval(xPosition, yPosition, diameter, diameter);
                  } else {      
                    int diameter = (radius*2);
                    int xPosition = x - radius;
                    int yPosition = y - radius;
                    pen.drawOval(xPosition, yPosition, diameter, diameter);  
                  }
                }

              }
            }

Now for the Frame Class. The Code:

Traffic.java is the literal JFrame piece to this project:

            /****************************
              * Traffic.java
              * 
              * 
              ******************************/
            import javax.swing.*; //Import swing package.
            import java.awt.*; //Import awt package.
            import java.awt.event.*; //Import events package.



            public class Traffic extends JFrame{

              public static void main(String[] args){

                //Create new JFrame.
                JFrame lightbox = new JFrame("Light Box");


                //Create new LightboxPanel.
                TrafficPanel traffic = new TrafficPanel();    


                //Set focus to the LightboxPanel in order to allow key inputs.
                traffic.setFocusable(true);   


                //Set the Default Close Operation to exit when the "x" button is selected.
                lightbox.setDefaultCloseOperation(EXIT_ON_CLOSE);


                //Add the LightboxPanel to the Lightbox JFrame.
                lightbox.add(traffic);


                //Pack the frame to the warranted preferred size of the LightboxPanel.
                lightbox.pack();


                //Set the frame's visibility to true.
                lightbox.setVisible(true);
              }
            }

Finally the panel class itself, TrafficPanel.java is more of the panel that calls methods to paint graphics from Lights.

The Code:

            //*****************************************************************************
            //  TrafficPanel.java   
            //
            //  Panel that holds graphics for the traffic light simulation.
            //*****************************************************************************

            import java.util.Scanner;  // import Scanner class from util package
            import javax.swing.JPanel;  // import JPanel class from swing package 
            import javax.swing.JButton;
            import java.awt.*;         // import awt package 
            import java.awt.event.*;  // import event package from awt package
            import java.util.Random; // import Random class from the util package

            public class TrafficPanel extends JPanel
            {  
              private Lights shapes;  
              private final int RED = 1; //Creates switch constant.
              private final int YELLOW = 2; //Creates switch constant.
              private final int GREEN = 3; //Creates switch constant.
              private final int ALL_ON = 5; //Creates switch constant.
              private final int ALL_OFF = 6; //Creates switch constant.
              private final int FLASHING_YELLOW = 4; //Creates Flashing Yellow
              private final int DARK_YELLOW = 9; //Case in case.
              private int flashingColor = YELLOW; //Case in case.
              private boolean flashingYellow = false; //Creates false by default flashingYellow boolean.
              private Color lightColor; //Color variable lightcolor.
              private int colorSwitch; //Switch integer using constants and lightcolor.
              private int typeSwitch; //Also similar to above.
              private int x, y, lightswitch; //Other integers.


              public TrafficPanel()
              {    
                Lights shapes = new Lights();
                //KeyListener trafficListener = new KeyListener();
                addKeyListener(new KeyListener());    
                //Set the size.
                //Dimension preferred = new Dimension(800, 920);
                setPreferredSize(new Dimension(800, 920));    
                //Set the background.
                //Color bisque = new Color(255, 228, 196);
                setBackground(new Color(255, 228, 196));
              }

              public void paintComponent (Graphics g)
              {
                super.paintComponent (g);

                //Normal state of panel. Initially offline.
                Lights shapes = new Lights();
                shapes.drawBox(g);    
                shapes.drawRedLight(g, false);
                shapes.drawYellowLight(g, false);
                shapes.drawGreenLight(g, false);
                shapes.drawFore(g);

                //Check state of light.
                switch(lightswitch){

                  case ALL_OFF:
                shapes.drawBox(g);    
                shapes.drawRedLight(g, false);
                shapes.drawYellowLight(g, false);
                shapes.drawGreenLight(g, false);
                shapes.drawFore(g);
                    break;



                  case ALL_ON:
                shapes.drawBox(g);    
                shapes.drawRedLight(g, true);
                shapes.drawYellowLight(g, true);
                shapes.drawGreenLight(g, true);
                shapes.drawFore(g);
                    break;

                  case RED:
                shapes.drawBox(g);    
                shapes.drawRedLight(g, true);
                shapes.drawYellowLight(g, false);
                shapes.drawGreenLight(g, false);
                shapes.drawFore(g);
                    break;


                  case GREEN:
                shapes.drawBox(g);    
                shapes.drawRedLight(g, false);
                shapes.drawYellowLight(g, false);
                shapes.drawGreenLight(g, true);
                shapes.drawFore(g);
                    break;


                  case YELLOW:
                shapes.drawBox(g);    
                shapes.drawRedLight(g, false);
                shapes.drawYellowLight(g, true);
                shapes.drawGreenLight(g, false);
                shapes.drawFore(g);
                    break;


                  case FLASHING_YELLOW: //If Flashing yellow.
                    switch(flashingColor){
                    case DARK_YELLOW:
                      flashingColor = YELLOW;
                      break;
                    case YELLOW:
                      flashingColor = DARK_YELLOW;
                      break;
                  }

                    try{
                      if(flashingColor == YELLOW){
                        shapes.flashOn(g);
                      }
                      Thread.sleep(250);
                      if(flashingColor == DARK_YELLOW){
                        shapes.flashOff(g); 
                      }
                    } catch(Exception e){}
                    break;    
                }



                repaint ();
              }

              /*********************
                * TrafficPanel$KeyListener.java
                * Author: Ian Effendi
                * 
                * Extension of KeyAdapter.
                * Inputs of 'o', 'f', and the spacebar all return actions.
                **********************/
              private class KeyListener extends KeyAdapter{


                //Occurs when a key is pressed.
                public void keyPressed(KeyEvent event){

                }

                //Occurs, only, when a key is released.
                public void keyReleased(KeyEvent event){

                  //If the key input is 'o'.
                  if(event.getKeyCode() == KeyEvent.VK_O){

                    flashingYellow = false;        

                    //Switch on what lightswitch is equal to.
                    switch(lightswitch){
                      case ALL_ON:
                        lightswitch = ALL_OFF;
                        break;
                      case ALL_OFF: 
                        lightswitch = ALL_ON;
                        break;
                      case RED: 
                        lightswitch = ALL_OFF;
                        break;
                      case YELLOW:
                        lightswitch = ALL_OFF;
                        break;
                      case GREEN:
                        lightswitch = ALL_OFF;
                        break;
                      case FLASHING_YELLOW:
                        lightswitch = ALL_OFF;
                        break;
                    }



                    //If the key input is the spacebar.
                  } else if(event.getKeyCode() == KeyEvent.VK_SPACE){

                    flashingYellow = false;

                    //Switch on what lightswitch is equal to.
                    switch(lightswitch){
                      case ALL_ON:
                        lightswitch = RED;
                        break;
                      case ALL_OFF:
                        lightswitch = ALL_OFF;
                        break;
                      case RED:
                        lightswitch = GREEN;
                        break;
                      case YELLOW:
                        lightswitch = RED;
                        break;
                      case GREEN:
                        lightswitch = YELLOW;
                        break;
                      case FLASHING_YELLOW:
                        lightswitch = YELLOW;
                        break;
                    }



                    //If the key input is 'f'.
                  } else if(event.getKeyCode() == KeyEvent.VK_F){

                    flashingYellow = true;

                    //Switch on what lightswitch is equal to.
                    switch(lightswitch){
                      case ALL_ON:
                        lightswitch = FLASHING_YELLOW;
                        break;
                      case ALL_OFF:
                        lightswitch = ALL_OFF;
                        break;
                      case RED:
                        lightswitch = FLASHING_YELLOW;
                        break;
                      case YELLOW:
                        lightswitch = FLASHING_YELLOW;
                        break;
                      case GREEN:
                        lightswitch = FLASHING_YELLOW;
                        break;
                      case FLASHING_YELLOW:
                        lightswitch = YELLOW;
                        break;
                    }


                    //If nothing is input, lightswitch returns itself.
                  } else {
                    int x = lightswitch;
                    lightswitch = x;
                  }      
                }


                //Occurs when an input is typed(not held).
                public void keyTyped(KeyEvent event){


                }
              }


            }//end of class

That is all the code. Please help any way you can. Any tips would also be appreciated.


Solution

  • When you get a NullPointerException, it means that you're trying to use a variable that has not been initialized, one that has not been referred to a concrete object.

    The solution is to look on the line throwing the NPE, and the NPE error text will tell you which line it is (here line 211 of ?LightBoxPanel -- a class that doesn't exist??), and then see why one of the variables that you're trying to use on that line is null. You likely have not assigned an object to the variable by calling Foobar myVariable = new Foobar(); on it.

    Also,

    • Don't create objects in paintComponent(...) as this method should be for painting and painting only.
    • Don't call repaint() in paintComponent(...).

    Edit: Your problem is that you're shadowing your variables. You're re-declaring them in the class constructor, meaning that the variables that you are initializing inside of the constructor are not the class fields that you think they are but rather are local to the constructor and exist only in the constructor. So when you initialize these local variables, you leave the class fields as null. The solution: don't re-declare the variables in the constructor.

    e.g., change this:

    class Lights {
       private final int RED = 1;
       private final int YELLOW = 2;
    
       // .... etc....
    
       private Rectangle grayBG, blackBG;
       private Circle red, green, yellow, redFore, greenFore, yellowFore;
    
       public Lights() {
          // the variables below are **local** to the constructor!
          Rectangle grayBG = new Rectangle(35, 35, 280, 830, true);
          Rectangle blackBG = new Rectangle(50, 50, 250, 800, true);
    

    to this:

    class Lights {
       private final int RED = 1;
       private final int YELLOW = 2;
    
       // .... etc....
    
       private Rectangle grayBG, blackBG;
       private Circle red, green, yellow, redFore, greenFore, yellowFore;
    
       public Lights() {
          grayBG = new Rectangle(35, 35, 280, 830, true); // *** note the difference
          blackBG = new Rectangle(50, 50, 250, 800, true); // *** note the difference