-1

I am having an issue with an assignment I have: I need to write a game with a timer component but I get a "Exception in thread "Timer-0" java.lang.NullPointerException" error. I am using the latest version of eclipse. Help would be appreciated.

The actual error:

Exception in thread "Timer-0" java.lang.NullPointerException at GameFrame$MyTimerTask.run(GameFrame.java:152) at java.util.TimerThread.mainLoop(Unknown Source) at java.util.TimerThread.run(Unknown Source)

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class GameFrame extends JFrame implements ActionListener {

    private final int NUM_BUTTONS1 = 5;
    private final int NUM_BUTTONS2 = 8;
    private final int NUM_BUTTONS3 = 10;
    private final int NUM_LEVELS = 3;

    private int[] columns,lines;
    private int current_size,hours,minutes,seconds,score,selection_counter;
    private int c1,c2,c3,c4,l1,l2,l3,l4;

    private Color color1,color2,color3,color4;
    private JButton [] buttons,selection;
    private JButton [] levels;
    private JPanel buttons_panel,levels_panel;
    private JTextField timer_field,score_field;
    private Timer timer;

    public GameFrame() {
        current_size = NUM_BUTTONS1;
        setLayout(new BorderLayout());
        buttons_panel = new JPanel();
        buttons_panel.setLayout(new GridLayout(NUM_BUTTONS1,NUM_BUTTONS1));
        //setup buttons
        buttons = new JButton[NUM_BUTTONS3 * NUM_BUTTONS3];
        for(int i = 0; i < buttons.length; i++) {
            buttons[i] = new JButton();
            switch((int)(Math.random() * 4)) {
                case 0:
                    buttons[i].setBackground(Color.BLUE);
                    break;
                case 1:
                    buttons[i].setBackground(Color.RED);
                    break;
                case 2:
                    buttons[i].setBackground(Color.GREEN);
                    break;
                case 3:
                    buttons[i].setBackground(Color.YELLOW);
                    break;
            }
        buttons[i].addActionListener(this);     
        }
        //add buttons to layout
        for(int i = 0; i < NUM_BUTTONS1 * NUM_BUTTONS1; i++)
            buttons_panel.add(buttons[i]);

        levels_panel = new JPanel();
        levels_panel.setLayout(new GridLayout(3,1));
        levels = new JButton[NUM_LEVELS];
        for(int i = 0; i < levels.length; i++) {
            levels[i] = new JButton("level "+ (i + 1));
            levels[i].addActionListener(this);
            levels_panel.add(levels[i]);
        }

        selection_counter = 0;
        selection = new JButton[4];
        columns = new int [4];
        lines = new int [4];

        hours = 0;
        minutes = 0;
        seconds = 0;
        timer = new Timer();
        timer.schedule(new MyTimerTask(), 0,1000);

        timer_field = new JTextField();
        timer_field.setText(hours + ":" + minutes + ":" + seconds);
        timer_field.setFont(new Font("random",0,50));
        timer_field.setHorizontalAlignment(JTextField.CENTER);
        timer_field.setBackground(Color.white);
        timer_field.setForeground(Color.green);
        add(timer_field,BorderLayout.SOUTH);

        score_field = new JTextField();
        score_field.setText("Game Score: " + score);
        score_field.setFont(new Font("random",0,50));
        score_field.setHorizontalAlignment(JTextField.CENTER);
        score_field.setBackground(Color.white);
        score_field.setForeground(Color.green);
        add(score_field,BorderLayout.NORTH);

        //add buttons layout and levels buttons layout
        add(buttons_panel,BorderLayout.CENTER);
        add(levels_panel,BorderLayout.WEST);
    }

    @Override
    public void actionPerformed(ActionEvent event) {
        //change levels
        if (event.getSource() == levels[0] || event.getSource() == levels[1] || event.getSource() == levels[2]) {
            if (event.getSource() == levels[0])
                current_size = NUM_BUTTONS1;
            else if (event.getSource() == levels[1])
                current_size = NUM_BUTTONS2;
            else if (event.getSource() == levels[2])
                current_size = NUM_BUTTONS3;
            buttons_panel.removeAll();
            //redefine grid Layout to match the new current_size
            buttons_panel.setLayout(new GridLayout(current_size, current_size));
            for(int i = 0; i < current_size * current_size; i++)
                buttons_panel.add(buttons[i]);
            newGame(); //changing levels requires starting a new game
        }
        //select a rectangle on the board
        else if (event.getSource() instanceof JButton) {
            selection[selection_counter++] = (JButton)event.getSource();
            if (selection_counter == 4) {
                selection_counter = 0;

                columns = findCoordinates(true);
                lines = findCoordinates(false);

                if (buttonsSelectionCheck()) {
                    updateBoard();
                }
            }

        }
        //update the window
        timer_field.setText(hours + ":" + minutes + ":" + seconds);
        score_field.setText("Game Score: " + score);
        buttons_panel.validate();
        repaint();      
    }

    public class MyTimerTask extends TimerTask {
        public void run() {
            seconds++;
            if (seconds == 60) {
                minutes++;
                seconds = 0;
            }
            if (minutes == 60) {
                hours++;
                minutes = 0;
            }
            timer_field.setText(hours + ":" + minutes + ":" + seconds);
        }
    }

    private void newGame() {
        score = 0;
        seconds = 0;
        minutes = 0;
        hours = 0;
        selection_counter = 0;
        selection[0] = null;
        selection[1] = null;
        selection[2] = null;
        selection[3] = null;

        for(int i = 0; i < buttons.length; i++) {
            switch((int)(Math.random() * 4)) {
                case 0:
                    buttons[i].setBackground(Color.BLUE);
                    break;
                case 1:
                    buttons[i].setBackground(Color.RED);
                    break;
                case 2:
                    buttons[i].setBackground(Color.GREEN);
                    break;
                case 3:
                    buttons[i].setBackground(Color.YELLOW);
                    break;
            }
        }       
    }

    private int[] findCoordinates(boolean choice) {
        int[] columns = new int[4];
        int[] lines = new int[4];

        for (int i = 0; i < selection.length; i++)
            for (int j = 0; j < buttons.length; j++)
                if (selection[i] == buttons[j]) {
                    if (choice)
                        columns[i] = j%current_size;
                    else
                        lines[i] = j/current_size;
                }
        if (choice)
            return columns;
        else
            return lines;
    }   

    public boolean buttonsSelectionCheck() {
        c1 = columns[0];
        c2 = columns[1];
        c3 = columns[2];
        c4 = columns[3];
        l1 = lines[0];
        l2 = lines[1];
        l3 = lines[2];
        l4 = lines[3];
        color1 = selection[0].getBackground();
        color2 = selection[1].getBackground();
        color3 = selection[2].getBackground();
        color4 = selection[3].getBackground();

        if (color1 != Color.GRAY && color1 == color2 && color2 == color3 && color3 == color4)
            if (c1 == c4 && c2 == c3 && l1 == l2 && l3 == l4 ) { 
                return true;
            }
        return false;
    }

    private void updateBoard() {
        int b_column,b_line;

        for (int i = 0; i < (current_size * current_size); i++) {
            b_column = i%current_size;
            b_line = i/current_size;
            if (b_column >= c1 && b_column <= c2 && b_line >= l1 && b_line <= l4) {
                if (buttons[i].getBackground() != Color.GRAY)
                    score+=10;
                buttons[i].setBackground(Color.GRAY);
            }
        }
    }

}
RoyAbr121
  • 11
  • 1
  • 2
  • 3
    there is no single day when i didn't see these errors posted by some one. Possible duplicate of https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it – Lokesh Pandey Oct 11 '17 at 09:36
  • 3
    Possible duplicate of [What is a NullPointerException, and how do I fix it?](https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – M. le Rutte Oct 11 '17 at 09:37
  • 1
    `timer_field` is created after the timer has already been started in the constructor. Thus, `timer_field` is null when used in the timer task at the beginning. – UninformedUser Oct 11 '17 at 09:46

2 Answers2

1

This line causes the MyTimerTask instance to be executed with a delay of 0 (no delay).

timer.schedule(new MyTimerTask(), 0,1000);

MyTimerTask accesses the field timer_field, which is initialized after the schedule statement.

timer_field = new JTextField();

So the timer_field is still null.

Solution:

    // timer.schedule(new MyTimerTask(), 0,1000);

    timer_field = new JTextField();
    timer_field.setText(hours + ":" + minutes + ":" + seconds);
    timer_field.setFont(new Font("random",0,50));
    timer_field.setHorizontalAlignment(JTextField.CENTER);
    timer_field.setBackground(Color.white);
    timer_field.setForeground(Color.green);

    timer.schedule(new MyTimerTask(), 0,1000);

So the schedule call should be a bit later.

Mitch
  • 79
  • 8
0

your inner class MyTimerTask uses timer_field before it's initialised. you can move these lines:

timer = new Timer();
timer.schedule(new MyTimerTask(), 0,1000);

to the end of the constructor, so that it is after this one which initialises timer_field:

timer_field = new JTextField();
Milo Bem
  • 1,033
  • 8
  • 20