【问题标题】:When I mouse drag to draw a Circle, the shape moves in certain situations当我用鼠标拖动画一个圆时,形状在某些情况下会移动
【发布时间】:2017-05-13 06:18:32
【问题描述】:
 @Override
    public Shape getShape() {
        final Ellipse2D.Double result = new Ellipse2D.Double();
        final double px = Math.min(getStart().getX(), getEnd().getX());
        final double py = Math.min(getStart().getY(), getEnd().getY());
        final double pw = Math.abs(getStart().getX() - getEnd().getX());
        result.setFrame(px, py, pw, pw);
        return result;
    }

所以这个 getShape() 将形状返回给绘制形状的类。 getStart() 获取鼠标点击的起点,getEnd() 获取鼠标释放时的起点。现在,当我拖动以绘制一个圆圈时,如果我向右或向下拖动圆圈按预期工作并扩展到鼠标,如果我向上或向左拖动光标,圆圈会按照它应该的方式扩展但是 strong> 圆形随着光标上下移动,我不知道为什么。

【问题讨论】:

  • 形状是从左上角到右下角绘制的。因此,您需要调整点,使较小的点代表左上角。虽然它使用Rectangle,但this example 演示了基本概念
  • 我阅读了那个帖子,但它并没有解决圆圈的拖动扩展,以及它如何上下移动。另外,您如何使用 Rectangle2D 而不仅仅是标准 Rectangle 来实现这一点。
  • 不要更新Rectangle 类,而是在每次需要更新时创建Rectangle2D 的新实例。而且,计算最小值/最大值的概念会起作用,一直使用它
  • 你仍然无法使用最小/最大值按预期工作,因为我的 Square 工具是一个单独的类,并且无法访问 g2d 进行绘图。我也不确定这对向左或向下拖动有什么帮助,这是用光标向上或向下移动我的形状
  • @MadProgrammer Image 这是用你的代码实现的最小值和最大值,看看在某些方向拖动时圆圈是如何上下移动的?

标签: java


【解决方案1】:

Java 中的形状基于左上角作为锚点,宽度/高度向下/向右绘制。

你需要计算点击点和拖动点之间的边界框

public Shape getShape() {
    final Ellipse2D.Double result = new Ellipse2D.Double();
    final double px = Math.min(getStart().getX(), getEnd().getX());
    final double py = Math.min(getStart().getY(), getEnd().getY());
    final double pw = Math.abs(getStart().getX() - getEnd().getX());
    result.setFrame(px, py, pw, pw);
    return result;
}

问题是,你还是用点击点和拖动点的差来计算宽度,pw应该是maxXminX值的差

所以this example 向您展示了如何计算锚点和大小属性

我阅读了那个帖子,但它没有解决圆圈的拖动扩展,以及它如何上下移动。

那你做错了

我正在尝试绘制一个圆,而不是一个没有相同宽度和高度(椭圆)的圆。

好的,所以应该总是显示圆是从锚点绘制的,所以当minXminY 小于clickPointx/y 点时,那么您需要将它们调整为 clickPoint 和大小的差异

因此,这将使它“出现”,就好像圆始终是从初始点击点绘制的一样

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class SelectionExample {

    public static void main(String[] args) {
        new SelectionExample();
    }

    public SelectionExample() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Point clickPoint;

        private Shape shape;
        private Rectangle box;

        public TestPane() {
            MouseAdapter ma = new MouseAdapter() {

                @Override
                public void mouseDragged(MouseEvent e) {
                    int minX = Math.min(e.getX(), clickPoint.x);
                    int minY = Math.min(e.getY(), clickPoint.y);
                    int maxX = Math.max(e.getX(), clickPoint.x);
                    int maxY = Math.max(e.getY(), clickPoint.y);

                    box = new Rectangle(minX, minY, maxX - minX, maxY - minY);
                    int size = Math.min(maxX - minX, maxY - minY);
                    if (minX < clickPoint.x) {
                        minX = clickPoint.x - size;
                    }
                    if (minY < clickPoint.y) {
                        minY = clickPoint.y - size;
                    }

                    shape = new Ellipse2D.Double(minX, minY, size, size);
                    repaint();
                }

                @Override
                public void mousePressed(MouseEvent e) {
                    clickPoint = new Point(e.getPoint());
                }

            };

            addMouseListener(ma);
            addMouseMotionListener(ma);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (shape != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setColor(new Color(0, 0, 255, 64));
                g2d.fill(shape);
                g2d.setColor(Color.BLUE);
                g2d.draw(shape);
                g2d.draw(box);
                g2d.dispose();
            }
        }
    }

}

【讨论】:

  • 好吧,你刚刚发布的 gif 不是一个正在创建的圆圈,而是一个椭圆,这就是为什么我试图将宽度和高度锁定为相同的值。它总是需要是一个圆,而不是一个椭圆。我可以让我的输出看起来就像那个 GIF,但我试图在拖动时实现它始终是一个圆圈。例如,在 Photoshop 中,如果您在拖动圆圈时按住 shift 键,它会保持锁定宽度和高度,因此它们始终相等。
  • “好吧,你刚刚发布的 gif,不是正在创建的圆圈,而是正在创建椭圆” - 所以,我已经演示了基本要求为了演示它如何“可以”实现,我相信您可以分析机制以找出制作圆圈的解决方案,这可能类似于确定您想要的两个 maxX/maxY 轴中的哪一个使用 - 这就是你从我这里得到的全部,因为我现在为你提供了两个基本的工作示例,剩下的就是让你决定你想使用哪个轴并计算你想使用的直径
  • 不应该根据光标所在的位置改变最小值,因为它使用 Ellipse2D.Double(x start, y start, height, width) 的参数,因此如果你向上拖动到右边,当它应该根据你所在的(象限)改变时,它会导致起点位于形状的右下角。
  • 好的,谢谢您的宝贵时间。不过,我不能真正将其标记为答案,因为它一开始并没有解决问题。我从来没有遇到过创建椭圆并能够拖动它的问题,我已经做到了并且效果很好,我正在尝试绘制一个圆而不是没有相同宽度和高度(椭圆)的圆。
  • @ThereIsNoSpoon 正如我解释的那样,这会计算起点和终点之间的差异,创建一个边界框,然后用于生成从minmax - min 的形状,这个适应 shape API 的要求
猜你喜欢
  • 1970-01-01
  • 2021-07-25
  • 2014-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-01
相关资源
最近更新 更多