-7

I want to make a program that has objects on the screen and then when you press down on them it will follow the mouse pointer until you then release the mouse and then it will no longer follow the mouse.

Here is the code i have to add balls to the screen so if it would be possible to just adapt the code it would be great. It is split into 3 classes

import java.awt.BorderLayout;
import java.awt.event.*;
 import java.util.Random;
import javax.swing.*;


public class DrawBalls {
JFrame frame = new JFrame();
final DrawPanel drawPanel = new DrawPanel();
JPanel controlPanel = new JPanel();
JButton createBallButton = new JButton("Add ball");

DrawBalls(){
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    controlPanel.add(createBallButton);
    frame.add(drawPanel);
    frame.add(controlPanel, BorderLayout.SOUTH);
     frame.pack();
    frame.setVisible(true);
     {
         drawPanel.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
            super.mouseMoved(e);
            for (Ball b : drawPanel.getBalls()) {
                if (b.getBounds().contains(me.getPoint())) {
                  //this has it being the same coordinates as the mouse i don't know   
                  //how to have it run constantly so when i move it, it doesn't work  

                  b.setx(me.getX()-(b.radius/2));
                  b.sety( me.getY()-(b.radius/2));   
                     drawPanel.repaint();
            }

        }
    }



     });
         createBallButton.addActionListener(new ActionListener() {
        Random rand = new Random();
        private int counter = 1;
 int noOfClicks = 1;

        public void actionPerformed(ActionEvent e) {


            if(noOfClicks<=10){

            int ballRadius = 10;
            int x = rand.nextInt(drawPanel.getWidth());
            int y = rand.nextInt(drawPanel.getHeight());

            //check that we dont go offscreen by subtarcting its radius unless its x and y are not bigger than radius
            if (y > ballRadius) {
                y -= ballRadius;
            }
            if (x > ballRadius) {
                x -= ballRadius;
            }

            drawPanel.addBall(new Ball(x, y, ballRadius, counter));//add ball to panel to be drawn
            counter++;//increase the ball number
        noOfClicks++;
        }
            }
    });        
}
public static void main(String[] args) {
   SwingUtilities.invokeLater(new Runnable() {
         @Override
        public void run() {
            new DrawBalls();
        }
    });
}

Ball class

import java.awt.*;
import java.awt.geom.*;

 public class Ball {
 private Color color;
 private int x, y;
 private int radius;
 private final int number;

Ball(int x, int y, int radius, int counter) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.number = counter;

    this.color = Color.RED;
  }
 public void draw(Graphics2D g2d) {
    Color prevColor = g2d.getColor();
    g2d.drawString(number + "", x + radius, y + radius);
    g2d.setColor(color);
    g2d.fillOval(x, y, radius, radius);
    g2d.setColor(prevColor);
}
public Rectangle2D getBounds() {
    return new Rectangle2D.Double(x, y, radius, radius);

}
int getNumber() {
    return number;
}
}

DrawPanel

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

 public class DrawPanel extends JPanel {
  ArrayList<Ball> balls = new ArrayList<Ball>();

   public void addBall(Ball b) {
      balls.add(b);
       repaint();
    }

   public ArrayList<Ball> getBalls() {
      return balls;
}
@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;

    for (Ball ball : balls) {
        ball.draw(g2d);
    }
}
    @Override
public Dimension getPreferredSize() {
    return new Dimension(300, 300);
}

}

Andrew
  • 29
  • 3
  • 8

1 Answers1

2

One way is to make your Ball class an actual Swing component. Then you can use the ComponentMover class.

Edit:

how do you make a class into a swing component

Basically, you move your draw(...) code into the paintComponent() method of JComponent. Here is a simple example that does all the custom painting for you because the painting is based on a Shape object. You would still need to modify the code to paint the "number".

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

public class ShapeComponent extends JComponent
{
    Shape shape;

    public ShapeComponent(Shape shape)
    {
        this.shape = shape;
        setOpaque( false );
    }

    public Dimension getPreferredSize()
    {
        Rectangle bounds = shape.getBounds();
        return new Dimension(bounds.width, bounds.height);
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D)g;

        g2d.setColor( getForeground() );
        g2d.fill( shape );
    }

    @Override
    public boolean contains(int x, int y)
    {
        return shape.contains(x, y);
    }

    private static void createAndShowUI()
    {
        ShapeComponent ball = new ShapeComponent( new Ellipse2D.Double(0, 0, 50, 50) );
        ball.setForeground(Color.GREEN);
        ball.setSize( ball.getPreferredSize() );
        ball.setLocation(10, 10);

        ShapeComponent square = new ShapeComponent( new Rectangle(30, 30) );
        square.setForeground(Color.ORANGE);
        square.setSize( square.getPreferredSize() );
        square.setLocation(50, 50);

        JFrame frame = new JFrame();
        frame.setLayout(null);
        frame.add(ball);
        frame.add(square);
        frame.setSize(200, 200);
        frame.setVisible(true);

        MouseListener ml = new MouseAdapter()
        {
            public void mouseClicked( MouseEvent e )
            {
                System.out.println( "clicked " );
            }
        };

        ball.addMouseListener( ml );
        square.addMouseListener( ml );
    }

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

The main difference between this approach and trashgod's suggestion to use an Icon is that mouse events will only be generated when the mouse in over the ball, not the rectangular corners of the ball since the contains(...) method respects the shape of what you are drawing.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • +1 See also this related [answer](http://stackoverflow.com/a/5312702/230513). – trashgod Mar 10 '13 at 18:54
  • how do you make a class into a swing component and how would it work with multiple balls – Andrew Mar 10 '13 at 19:03
  • @Andrew: See [*How to Use Icons*](http://docs.oracle.com/javase/tutorial/uiswing/components/icon.html), using e.g. [`ColorIcon`](http://stackoverflow.com/a/3072979/230513). – trashgod Mar 10 '13 at 19:38
  • Didn't notice until now that you are also painting text on the ball. @trashgod suggestion makes this really easy. You can add both the Icon and the Text to the label and configure the label to paint the text at the center of the Icon. – camickr Mar 10 '13 at 20:50
  • @Andrew: You might also be able to leverage the label's text alignment, as shown [here](http://stackoverflow.com/a/2834484/230513). – trashgod Mar 11 '13 at 00:27