跟随鼠标位置画圈直到单击

时间:2018-10-29 12:31:10

标签: java graphics2d mouselistener

我想创建一个项目,其中包括在Java GUI上绘制一个圆。单击圆或圆周围的区域时,圆应“粘”在光标上并跟随其移动,直到再次单击鼠标。然后圆圈应该留在您单击的位置。

我所做的一切,直到程序检测到您单击了圆圈。这里的圆圈是g2使用g2.fillOval方法制作的图形。

有两个类:

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);
    }
}

请让我知道继续前进的最佳方法。

1 个答案:

答案 0 :(得分:1)

您需要添加MouseMotionListener并实现mouseMoved(),或者根据需要添加mouseDragged()

有多种方法可以做到这一点。这取决于您要单击移动还是拖动。区别是:

  • 点击移动:按下,释放,移动,按下,释放
  • 拖动:按下,移动,释放

点击移动

在这种情况下,您需要实施

  • mouseClicked()观察者的MouseListener处理程序可以切换boolean并记住机芯的开始位置。
  • mouseMoved()观察者的MouseMotionListener执行实际的移动。

赞:

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();
    }
}

拖动

在这种情况下,您需要实施 * mousePressed()观察者的MouseListener处理程序,用于拖动的起始位置。 * mouseDragged()观察者的MouseMotionListener处理程序,用于跟踪拖动运动。

与之前的代码唯一的区别是您不需要该布尔切换。

关于原始答案的注释

在我的原始答案中,我建议在MouseMotionListener的相应事件中动态添加/删除MouseListener。我不再认为这是一个好主意,因为没有“便宜”的方法来检测观察者是否已经注册,因此无论如何都需要布尔值。

关于代码的注意事项

我认为从Graphics2D方法初始化paint()类型的字段不是一个好主意。屏幕上的Graphics对象的有效性可能与repaint()调用树绑定。在repaint()调用树之外调用其方法可能会导致未定义的行为。 Graphics对象的生存期是repaint()调用树,而不是ExampleGUI对象,并且代码应通过不将其缓存在字段中来反映这一点。

扩展使用的UI类(您的extends JFrame)是一种反模式,并且违反了Liskov替换原则。 (仍然)过度使用了继承。考虑使用委托而不是继承。