Reputation: 155
I want to make a project that includes drawing a circle on a Java GUI. When the circle or an area around the circle is clicked, the circle should "stick" to the cursor and follow it until a mouse click happens again. Then the circle should stay where you clicked.
I made everything up to the point where the program detects that you clicked onto the circle. Circle here is a graphic made by g2
with the g2.fillOval
method.
There are two classes:
MainClass.java
public class MainClass {
public static void main(String[] args){
ExampleGUI g = new ExampleGUI();
}
}
ExampleGUI.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class ExampleGUI extends JFrame {
Graphics2D g2;
Point point = new Point(150,150);
ExampleGUI() {
MouseListener ml = new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
Point clicked = new Point(e.getLocationOnScreen().x - getX(),e.getLocationOnScreen().y - getY());
if(clickedaroundpoint(clicked)){
System.out.println("Clicked on Point");
}
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
};
this.addMouseListener(ml);
setTitle("FlamingoBall");
setSize(300,300);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
this.setVisible(true);
}
private boolean clickedaroundpoint(Point clicked) {
if(Point.distance(point.x+2,point.y+2,clicked.x,clicked.y)<=5){
return true;
}
return false;
}
public void paint(Graphics g) {
super.paintComponents(g);
g2 = (Graphics2D) g;
g2.setColor(Color.RED);
g2.fillOval(point.x,point.y,7,7);
}
}
Please let me know what the best way is to keep going.
Upvotes: 0
Views: 836
Reputation: 17935
You need to add a MouseMotionListener
and implement mouseMoved()
, or mouseDragged()
if you like.
There are multiple ways how you could do that. It depends on whether you want click-move or drag. The difference is:
In that case you need to implement
mouseClicked()
handler of the MouseListener
observer to toggle a boolean
and remember the start position of the movement.mouseMoved()
of the MouseMotionListener
observer to perform the actual movement.Like this:
class Mover implements MouseListener, MouseMotionListener {
private boolean moving;
private Point movementOrigin;
public void mouseClicked(MouseEvent e) {
if (moving = !moving)
movementOrigin = e.getPoint();
}
public void mouseMoved(MouseEvent e) {
if (!moving) return;
Point pos = e.getPoint();
Point delta = new Point(pos.getX() - movementOrigin.getX(), pos.getY() - movementOrigin.getY());
// TODO Relocate the circle with that delta
repaint();
}
}
In that case, you need to implement
* The mousePressed()
handler of the MouseListener
observer for the start position of the drag.
* The mouseDragged()
handler of the MouseMotionListener
observer for following the drag movement.
The only difference to the code before is that you do not need that boolean toggle.
In my original answer I suggested to dynamically add/remove the MouseMotionListener
in the corresponding event of the MouseListener
. I no longer think that this is a good idea, because there is no "cheap" way to detect whether an observer was already registered, and thus a boolean would be needed anyway.
I don't think that having a field of type Graphics2D
initialized from a paint()
method is a good idea. The validity of an on-screen Graphics
object is probably bound to the repaint()
call tree. Calling its methods outside of the repaint()
call tree is probably going to result in undefined behavior. The lifetime of the Graphics
object is the repaint()
call tree, not the ExampleGUI
object, and the code should reflect that by not caching it in a field.
Extending UI classes (your extends JFrame
) for usage is an anti-pattern and violates the Liskov Substitution Principle. Inheritance is (still) overused. Consider using delegation instead of inheritance.
Upvotes: 1