MouseListener not giving accurate mouse location

214 views Asked by At

I am attempting to have a circle appear on the screen and follow the mouse around. (Eventually I'm going to turn it into a game with ray casting) I am using a MouseMotionListener and am trying to use the mouseMoved method to get accurate mouse location within my JPanel. The problem is though that the farther I move my mouse down the screen, the less accurate it becomes. By the time my mouse gets to the bottom, it is drawing circles about 20 pixels above. It is not a lagging thing because it never catches up, it is always a few pixels above where it should be.

I've tried using different methods that call from MouseEvents and have tried using MousePointerInfo but none work correctly. It does seem to work when I have the JFrame set to undecorated, but obviously that does not look good for a program and thus I want to avoid that.

public class Driver {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Moonlight");
        frame.setSize(700, 700);
        frame.setLocation(350, 50);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(new MoonlightPanel());
        frame.setVisible(true);
    }
}


public class Panel extends JPanel {
    private BufferedImage myImage;
    private Graphics myBuffer;
    private Timer t;
    public Panel () {
        myImage = new BufferedImage(700, 700, BufferedImage.TYPE_INT_RGB);
        myBuffer = myImage.getGraphics();
        t = new Timer(0, new Listener());
        t.start();
        addMouseMotionListener(new Mouse());
    }

    private class Listener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            drawBackground();

            /*try {
                Point pos = getMousePosition();
                myBuffer.setColor(Color.WHITE);
                myBuffer.fillOval(pos.x - 10, pos.y - 10, 20, 20);
            }
            catch(NullPointerException en) {}*/

            repaint();
        }
    }

    private class Mouse implements MouseMotionListener {
        public void mouseMoved(MouseEvent e) {
            Point pos = new Point(e.getX(), e.getY());
            System.out.println(pos);
            myBuffer.setColor(Color.BLUE);
            myBuffer.fillOval(pos.x - 10, pos.y - 10, 20, 20);
        }
        public void mouseDragged(MouseEvent e) {}
    }

    public void drawBackground() {
        setBackground(Color.BLACK);
    }

    public void paintComponent(Graphics g) {
        g.drawImage(myImage, 0, 0, getWidth(), getHeight(), null);
    }
}
1

There are 1 answers

6
Abra On

Your code is much more complex than it needs to be. The Panel class members are unnecessary. All you need to do is save the mouse location in the mouseMoved() method - in a class member variable - and reference it in the paintComponent() method to draw your blue circle. The below code is a stripped-down version which displays a blue circle that follows the mouse pointer around on the screen.

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Point;

import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class MoonLite extends JPanel implements MouseMotionListener {
    private Point pt;

    public MoonLite() {
        setBackground(Color.BLACK);
        setForeground(Color.BLUE);
        addMouseMotionListener(this);
    }

    public void mouseMoved(MouseEvent e) {
        pt = e.getPoint();
        repaint();
    }

    public void mouseDragged(MouseEvent e) {
        // Do nothing.
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (pt != null) {
            g.fillOval(pt.x - 10, pt.y - 10, 20, 20);
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame frame = new JFrame("Moonlight");
                frame.setSize(700, 700);
                frame.setLocation(350, 50);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setContentPane(new MoonLite());
                frame.setVisible(true);
            }
        });
    }
}