【问题标题】:Dragging A Circle on a JFrame在 JFrame 上拖动一个圆圈
【发布时间】:2009-12-10 07:26:56
【问题描述】:

我试图让一个圆圈出现在屏幕上,然后当用户点击圆圈内时,使他们能够在按下鼠标时将圆圈拖动到鼠标所在的位置。

这是我到目前为止的代码,拖动可以工作,但它允许用户在不按下圆圈内部的情况下拖动,就在按下屏幕上的任何位置时。

我希望我不会太困惑

这是我的代码,如果有人能告诉我需要更正的代码,它将为我节省更多时间。

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

public class DragCircle extends JFrame {
    private static final long serialVersionUID = 1L;

    public static int size = 400;

    public static int r = 10;

    private int x;

    private int y;

    private int cX;

    private int cY;

    private int dX;

    private int dY;

    private MouseHandler mh;

    boolean isCircleClicked = false;

    public static void main(String[] args) {
        DragCircle c1 = new DragCircle();
        c1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

    public DragCircle() {

        super("Drag circle");

        cX = r + 100;
        cY = r + 100;

        mh = new MouseHandler();
        addMouseListener(mh);
        addMouseMotionListener(mh);

        setSize(size, size);
        setVisible(true);

    }

    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(Color.RED);
        g.fillOval(cX, cY, r * 2, r * 2);

    }

    private class MouseHandler extends MouseAdapter implements
            MouseMotionListener {
        public void mousePressed(MouseEvent me)

        {

            if ((cX - me.getX()) * (cX - me.getX()) + (cY - me.getY())
                    * (cY - me.getY()) < r * r) {
                isCircleClicked = true;
            }
        }

        public void mouseDragged(MouseEvent me) {
            if (isCircleClicked) {

                x = me.getX() - dX;
                y = me.getY() - dY;
                cX = x + r;
                cY = y + r;
                repaint();
            }
        }

        public void mouseReleased(MouseEvent e) {
            isCircleClicked = false;
        }

    }

}

【问题讨论】:

  • 你对 mouseReleased 的看法是正确的,我会把它放进去,它确实是这样编译的。

标签: java swing jframe drag geometry


【解决方案1】:

你的一个问题是

public void mouseDragged(MouseEvent me) {
    if (isCircleClicked = true) {

您在这里所做的是每次拖动鼠标时将isCircleClicked 设置为true。此外,此语句的计算结果为 true,这就是为什么您可以在任何地方拖动并移动圆圈的原因。将其更改为

 if (isCircleClicked) {

你应该没问题。

下一个问题是您永远不会将isCircleClicked 重置为false。您应该在 mouseReleased 中执行此操作,或者更改您的 mousePressed,如下所示:

public void mousePressed(MouseEvent me) {
    isCircleClicked =
        (cX - me.getX()) * (cX - me.getX()) +
        (cY - me.getY)) * (cY - me.getY()) < r * r;
}

这将相应地设置isCircleClicked

不过,还有一些事情要做。在当前表单中,您需要开始拖动到中心点的左上角,如下图所示:

+------+ | | | .-|-。 | / | \ +--------+ | \ / '-_-'

这是因为您的绘图:fillOval 采用椭圆形的左上角以及边界矩形的宽度和高度。 不是中心点和各自的直径。因此,您需要按如下方式调整他的内容:

g.fillOval(cX - r, cY - r, r * 2, r * 2);

注意左上角半径的偏移量。

此外,您的拖动代码需要做更多的工作。您当前假设用户拖动圆圈的center。您需要做的是保存鼠标单击的坐标,然后根据鼠标相对于最后一点的移动来移动圆圈。当前,您正在相对于圆心移动,因此要使移动变得更好,您必须开始精确地在圆心处拖动。我会把它作为练习留给你:-)

此外,您的侦听器类已经继承自 MouseAdapter,因此您无需显式实现 MouseMotionListener,因为 MouseAdapter 已经实现了它。

【讨论】:

  • 我只是更新了代码..我编辑了帖子以显示我做了什么..但它的行为很奇怪,当我运行它时,圆圈根本没有被拖动
  • 尝试向圆圈的左侧和顶部拖动一点。这个对我有用。现在我只需要找出为什么它没有正确地对圆圈进行命中测试。
【解决方案2】:

您的程序结构错误。您永远不应该覆盖 JFrame 的 paint(...) 方法。这是一个古老的 AWT 技巧,不应该与 Swing 一起使用。

阅读 Custom Painting 上的 Swing 教程部分,了解正确绘画方法的示例。基础是覆盖 JPanel 的 paintComponent(...) 方法,然后将面板添加到框架的内容窗格中。

关于您的问题,更好的解决方案是创建一个 Ellipse2D 对象来表示您的圆。那么自定义绘画就可以使用Graphics2D类的drawShape(...)方法了。然后在你的 MouseListener 代码中,你可以使用 Shape.contains(...) 方法来查看鼠标是否被点击在圆圈上。

【讨论】:

  • 命中测试一个圆圈是微不足道的,命中测试代码对我来说看起来是正确的。我认为只有当 OP 首先移动圆圈并且 然后 尝试将其拖出时才会发生这种情况(isCircleClicked 仍设置为 true,从而移动圆圈。
  • 显然它不是微不足道的,因为您必须修改代码以考虑正确的坐标。这就是使用 Shape Object 更简单的原因,因此您不必担心细节,只需调用 contains(...) 方法。我尝试推荐使用 API 的解决方案,而不是重新发明轮子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-24
  • 2018-01-29
  • 1970-01-01
  • 2021-09-16
  • 2012-11-12
相关资源
最近更新 更多