2

I'm a beginner in Java, and I'm trying to create an application that draws a rectangle where ever the cursor is located. I've already done everything, but I can't get the mouseMoved(MouseEvent) method to repaint the JPanel. Without the repaint, the rectangle is only drawn once and that's it. With the repaint, it compiles fine, but when I run it, every time the mouse is moved, I get this big "Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException" error.

So, can anyone please help me out on this?

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.*;

public class Game extends JPanel implements MouseMotionListener 
{
    public static void main(String[] args) {
        new Game().game();
    }
    JPanel panel;
    JButton button2;
    JButton button;
    public void game() {
        JPanel panel = new Game();
        button = new JButton("Ok");
        panel.setLayout(new FlowLayout());
        panel.add(button);

        button2 = new JButton("Cancel");

        JFrame frame = new JFrame("Game");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500,500);
        frame.setResizable(false);
        frame.add(panel);

        frame.setVisible(true); 
        panel.addMouseMotionListener(this);
    }

    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        PointerInfo a = MouseInfo.getPointerInfo();
        Point b = a.getLocation();
        int x = (int) b.getX();
        int y = (int) b.getY();
        g.fillRect(x,y,100,100);        
    }

    public void mouseMoved(MouseEvent evt) {
        panel.repaint; //This is the line of code that I need help with. Thanks!
    }
    public void mouseDragged(MouseEvent evt) {}
}
nIcE cOw
  • 24,468
  • 7
  • 50
  • 143
Ahmed Tawfik
  • 63
  • 2
  • 8
  • 2
    1) Use a consistent and logical indent for code blocks. The indentation of the code is intended to help people understand the program flow. 2) Don't set the size of top level containers. Instead layout the content & call `pack()`. – Andrew Thompson Jul 10 '13 at 13:54
  • Thanks for the comment Andrew. But if I don't resize the JFrame, then how will it know the size of the window? And what does pack() do? Thanks again! – Ahmed Tawfik Jul 12 '13 at 11:02
  • *"And what does pack() do?"* If you had read the JavaDocs for the method, it is likely you would not have to ask those questions of me! – Andrew Thompson Jul 12 '13 at 12:16

2 Answers2

4

Change this :

public void game() {
JPanel panel = new Game();

to this :

public void game() {
panel = new Game();

You are just creating a local variable in the first case. To fix this you need to instantiate the class variable.

Oliver Watkins
  • 12,575
  • 33
  • 119
  • 225
4

Hopefully the comments in the code example, be able to tell what you doing wrong in your code :-), otherwise there is always a reason to put forth your doubts...

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class Game extends JPanel {
    /*
     * Now x and y are instance variables,
     * whose values you can change at each
     * MouseMove Event, and call repaint()
     * to see the effects
     */

    private int x;
    private int y;
    private MouseAdapter mouseActions =
        new MouseAdapter() {
        @Override
        public void mouseMoved(MouseEvent me) {
            /*
             * Now as the Mouse moves, we simply
             * updating the instance variables,
             * i.e. x and y to the new values
             * of the Mouse Location and calling
             * repaint() to draw the rectangle.
             * Since this class (Game) extends JPanel,
             * hence all the functions of the JPanel
             * belongs to this class, hence like
             * as we call any other method of this
             * class, without using the object,
             * we can call repaint, likewise.
             */
            x = me.getX();
            y = me.getY();
            repaint();
        }
    };

    /*
     * This JPanel panel is unnecessary in 
     * this case, since the class itself 
     * extends JPanel, hence you can use
     * this (keyword) to access the instance
     */
    //JPanel panel;
    // Not needed for this case.
    //JButton button2;
    //JButton button;
    public void game() {

        JFrame frame = new JFrame("Game");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setResizable(false);
        addMouseMotionListener(mouseActions);
        /*
         * Here this means the instance
         * of the current class
         */
        frame.add(this);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    /*
     * While overriding methods of the 
     * super class, try to keep the 
     * ACCESS SPECIFIER, as close to
     * the original thingy as possible
     * In this case, it's protected
     * and not public
     */
    @Override
    protected void paintComponent(Graphics g) {

        /*
         * Do not perform calculation in this method
         * atleast.
         */
        super.paintComponent(g);
        g.fillRect(x, y, 100, 100);
    }

    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                new Game().game();
            }
        };
        EventQueue.invokeLater(runnable);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(500, 500);
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
nIcE cOw
  • 24,468
  • 7
  • 50
  • 143
  • 2
    +1 nice, if I had to nitpick, rather override `getPreferredSize` of `JPanel` and return the dimensions you want, and remove `JFrame#setSize()` and use `pack()` before setting `JFrame` visible :) – David Kroukamp Jul 10 '13 at 18:07
  • 2
    @DavidKroukamp : Please, if you may do those changes, I be too obliged. I am on my iPad, so formatting the code will be a bit tough for me. Suggestions are too good, else I have to wait till morning to do he edits :( For the rest THANKYOU and KEEP SMILING.:-) – nIcE cOw Jul 10 '13 at 18:14
  • 3
    @nIcEcOw: I took the liberty making the changes that David suggested. – trashgod Jul 10 '13 at 18:36
  • 2
    Ahhhh I Would a but @trashgod did it for us :). Thank you sir! – David Kroukamp Jul 10 '13 at 18:55
  • 2
    Overriding [`getPreferredSize()`](http://stackoverflow.com/q/7229226/230513) is my new _ad hoc_ rationale for extending `JPanel`. :-) – trashgod Jul 10 '13 at 19:01
  • Thank you so much for your answer nice cow! And thank you everyone else for your comment! But just a few questions: How come in the paintComponent method you call the x and y variable, when their values were set in another method? Wouldn't it give like a null value? And what does override mean? Thanks alot again! – Ahmed Tawfik Jul 12 '13 at 11:06
  • 1
    `x` and `y` here are instance variables, so you can use them everywhere in the class (they will have the same values, no matter where ever you use them). You can make any number of methods, use `System.out.println("X : " + x + "\nY : " + y);` to see that. More info on [Understanding Instance and Class Members](http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html). That `@Override` actually lets you be sure, that you actually overriding a method of the super class, and not creating your own and thinking that it is actually overriding some super class's method. – nIcE cOw Jul 12 '13 at 11:34
  • 1
    __Continued...__ Try to change the spelling of `paintComponent()` to something else, like `pintComponent()` with that `@Override` attached, you will get a compile time error, without `@Override` you can compile your program. More info on this is found on [Annotations](http://docs.oracle.com/javase/tutorial/java/annotations/) – nIcE cOw Jul 12 '13 at 11:37