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

我已经完成了所有操作,直到程序检测到您单击了圆圈。这里的 Circle 是由 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); 
    } 
} 

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

请您参考如下方法:

您需要添加一个 MouseMotionListener 并实现 mouseMoved()mouseDragged()(如果您愿意)。

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

  • 点击移动:按下、松开、移动、按下、松开
  • 拖动:按下、移动、释放

点击-移动

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

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

像这样:

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

拖动

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

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

关于原始答案的说明

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

关于代码的注释

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

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


评论关闭
IT干货网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!