在JFrame上拖动圆圈

时间:2009-12-10 07:26:57

标签: java swing jframe drag geometry

我想在屏幕上显示一个圆圈,然后当用户点击圆圈内侧时,启用它们可以拖动鼠标按下时所在的圆圈。

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

我希望我不会太困惑

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

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

    }

}

2 个答案:

答案 0 :(得分:2)

你的一个问题是

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

请注意半径到左侧和顶部的偏移量。

此外,您的拖动代码还需要更多工作。您目前假设用户拖动了圈子的中心。您需要做的是保存鼠标单击的坐标,然后根据鼠标相对于最后一点的移动移动圆。目前你正在相对于圆的中心移动,所以为了让运动变得更好,你必须开始正好在圆的中心拖动。我会把它作为练习留给你: - )

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

答案 1 :(得分:0)

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

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

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