user2624441
user2624441

Reputation:

Java repaint issue-seeing ovals each move

Heres part of my simple code.I want to achieve moving oval to cursors X axis location after clicking left button.Problem is that I can see only last position of oval (when it already stops).I think repaint method in while block doesnt work as I would like.I would like to see each move of oval as its getting into position of cursor.Thank you for suggestions.

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

public class Testfile extends JPanel implements Runnable,MouseListener{
public static JFrame frame;
public int x;
public int y;
public int pointX;
public int pointY;

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

     g.fillOval(x, y, 20, 20);
 }

 public static void main(String args[])throws InterruptedException{
     Testfile z=new Testfile();
     z.setBackground(Color.cyan);

     frame=new JFrame("Test");
     frame.setSize(500,500);
     frame.add(z);
     frame.addMouseListener(z);
     frame.setVisible(true);
}
public void mouseClicked(MouseEvent e){
    pointX=(int)MouseInfo.getPointerInfo().getLocation().getX();
    pointY=(int)MouseInfo.getPointerInfo().getLocation().getY();

    try{
    while(x!=pointX){
        x=x+1;
        Thread.sleep(10);
        repaint();
        }
    }
        catch(InterruptedException v){System.out.println(v);}
}

Upvotes: 0

Views: 63

Answers (2)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285403

.I think repaint method in while block doesnt work as I would like

Your problem has nothing to do with repaint "not working" and all to do with your tying up the Swing event thread. If you run a long-running process on the Swing Event Dispatch Thread (or EDT), the thread responsible for painting the GUI and interacting with the user, your GUI freezes and won't paint itself or respond until the EDT is released.

Solution: don't use a while (true) loop or Thread.sleep(...) on the Swing event thread. Also:

  • Use a Swing Timer instead to act as your animation "loop".
  • Another possible solution is to use a background thread to do the Thread.sleep(...), but in my opinion this is not worth the trouble since a Swing Timer will work so well and is easier to implement correctly.

Also:

  • Don't add your MouseListener to the JFrame but rather to your drawing JPanel. Otherwise you'll find that you'll be off in the y direction by the height of the title bar.
  • Use the mousePressed(...) method not mouseClicked(...) since the former is more forgiving.
  • Get the deltaX and deltaY on mousePressed, the direction that the circle should go by subtracting x from pointX and y from pointY.
  • I've gotten your code to work by checking the Manhattan distance between x and y and pointX (manHattanDistance = Math.abs(x - pointX) + Math.abs(y - pointY);) and pointY, and stopping the timer if it gets below a minimum. I've also saved the prior Manhattan distance and have checked the differences between the old and new one to make sure that the oval doesn't over-shoot, kind of as a fail-safe.
  • Use doubles to hold your x, y, pointX, pointY, etc, and cast to int when drawing.
  • Don't forget to cast your Graphics object to a Graphics2D and use RenderingHints to turn antialiasing on. This will make for prettier graphics.
  • Avoid "magic" numbers. Use constants instead.
  • Consider using x and y for the center of your circle rather than the left upper corner.

For example, my paintComponent(...) method could look like:

public void paintComponent(Graphics g) {
  super.paintComponent(g);
  Graphics2D g2 = (Graphics2D) g;
  g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);

  // RADIUS is an int const and = 10
  g.fillOval((int) x - RADIUS, (int) y - RADIUS, 2 * RADIUS, 2 * RADIUS);
}

Upvotes: 3

user1111284
user1111284

Reputation: 906

As above. you need to do these things on separate threads.

Sometimes you will need to decrement x so check if it's already bigger than the the point clicked, or the program will keep incrementing it indefinitely. Also you'll probably want to do the same with y

Upvotes: 0

Related Questions