跟随鼠标位置的圆圈直到被点击
Circle following the mouse position until clicked
我想做一个项目,包括在 Java GUI 上画一个圆。单击圆圈或圆圈周围的区域时,圆圈应 "stick" 到光标并跟随它,直到再次单击鼠标为止。然后圆圈应该停留在您点击的位置。
我做了一切,直到程序检测到您点击了圆圈。这里的圆是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()
处理程序,用于跟随拖动运动。
与之前代码的唯一区别是您不需要那个布尔切换。
关于原始答案的注释
在我原来的回答中,我建议在 MouseListener
的相应事件中动态 add/remove MouseMotionListener
。我不再认为这是一个好主意,因为没有 "cheap" 检测观察者是否已经注册的方法,因此无论如何都需要一个布尔值。
代码注意事项
我认为从 paint()
方法初始化 Graphics2D
类型的字段不是一个好主意。屏幕上 Graphics
对象的有效性可能绑定到 repaint()
调用树。在 repaint()
调用树之外调用它的方法可能会导致未定义的行为。 Graphics
对象的生命周期是 repaint()
调用树,而不是 ExampleGUI
对象,代码应该通过不在字段中缓存它来反映这一点。
扩展 UI 类(您的 extends JFrame
)使用是一种反模式,违反了 Liskov 替换原则。继承(仍然)被过度使用。考虑使用委托而不是继承。
我想做一个项目,包括在 Java GUI 上画一个圆。单击圆圈或圆圈周围的区域时,圆圈应 "stick" 到光标并跟随它,直到再次单击鼠标为止。然后圆圈应该停留在您点击的位置。
我做了一切,直到程序检测到您点击了圆圈。这里的圆是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()
处理程序,用于跟随拖动运动。
与之前代码的唯一区别是您不需要那个布尔切换。
关于原始答案的注释
在我原来的回答中,我建议在 MouseListener
的相应事件中动态 add/remove MouseMotionListener
。我不再认为这是一个好主意,因为没有 "cheap" 检测观察者是否已经注册的方法,因此无论如何都需要一个布尔值。
代码注意事项
我认为从 paint()
方法初始化 Graphics2D
类型的字段不是一个好主意。屏幕上 Graphics
对象的有效性可能绑定到 repaint()
调用树。在 repaint()
调用树之外调用它的方法可能会导致未定义的行为。 Graphics
对象的生命周期是 repaint()
调用树,而不是 ExampleGUI
对象,代码应该通过不在字段中缓存它来反映这一点。
扩展 UI 类(您的 extends JFrame
)使用是一种反模式,违反了 Liskov 替换原则。继承(仍然)被过度使用。考虑使用委托而不是继承。