简体   繁体   English

使用鼠标拖动在 Java 中绘制曲线

[英]Drawing a curve in Java using mouse drag

I am new to java and I am trying to draw a curve.我是 Java 新手,我正在尝试绘制曲线。 The functionality I am trying to implement is that the curves should be defined by a mouse drag followed by a mouse click.我试图实现的功能是应该通过鼠标拖动然后单击鼠标来定义曲线。 Once the drag action is done, I want a line to be drawn from the start of the drag to the end.拖动动作完成后,我希望从拖动开始到结束绘制一条线。 Clicking on the canvas after that should be considered the third point necessary to define the curve and the line drawn should be changed into a curve.之后单击画布应视为定义曲线所需的第三个点,绘制的线应更改为曲线。
How do I do that?我怎么做? I've gone through different posts here about how to draw Bezier curves but I am super confused.我在这里浏览了关于如何绘制贝塞尔曲线的不同帖子,但我非常困惑。 Here's a chunk of my code to draw rectangles, ovals and lines using mouse events:这是我使用鼠标事件绘制矩形、椭圆和线条的一段代码:

   public void mousePressed(MouseEvent e) {

        xCoordinateInitial = e.getX(); //Initialize x-coordinate to the mouse x-coordinate
        yCoordinateInitial = e.getY() + shiftInY; //Initialize y-coordinate to the mouse y-coordinate
        System.out.println("X-coordinate: " + xCoordinateInitial);
        System.out.println("Y-coordinate: " + yCoordinateInitial);
    }

    public void mouseReleased(MouseEvent e) {

        Graphics2D G = (Graphics2D) getGraphics();
        G.setStroke(new BasicStroke(lineThickness));
        G.setColor(colorSelected);
        G.setPaint(colorSelected);
        xCoordinateFinal = e.getX(); //Set final x-coordinate to the mouse x-coordinate after drag
        yCoordinateFinal = e.getY() + shiftInY; //Set final y-coordinate to the mouse y-coordinate after drag
        int x = xCoordinateInitial;
        int y = yCoordinateInitial;
        int width = xCoordinateFinal - xCoordinateInitial; //Setting width
        int height = yCoordinateFinal - yCoordinateInitial; //Setting height



        if (yCoordinateFinal < yCoordinateInitial) {
            y = yCoordinateFinal;
            height = yCoordinateInitial - yCoordinateFinal;
        }

        if (xCoordinateFinal < xCoordinateInitial) {
            x = xCoordinateFinal;
            width = xCoordinateInitial - xCoordinateFinal;
        }


        // Shape Selection
        switch (shapeSelected) {
            case Line:

                G.drawLine(xCoordinateInitial, yCoordinateInitial, xCoordinateFinal, yCoordinateFinal);
                break;

            case Rectangle:
                G.fillRect(x, y, width, height);
                break;

            case Oval:
                G.fillOval(x, y, width, height);
                break;

            case Curve :

                // To implement

        }

    }
});

I tried to understand the following but I couldn't make it work:我试图理解以下内容,但我无法让它工作:

                        Path2D p = new GeneralPath();
                        p.moveTo(x1, y1);
                        p.curveTo(bx1, by1, bx2, by2, x2, y2);
                        G.draw(p);

Let's start by having a read through the JavaDocs for Path2D#curveTo让我们首先阅读Path2D#curveTo的 JavaDocs

public final void curveTo(double x1, public final void curveTo(double x1,
double y1,双y1,
double x2,双x2,
double y2,双y2,
double x3,双x3,
double y3)双 y3)

Adds a curved segment, defined by three new points, to the path by drawing a Bézier curve that intersects both the current coordinates and the specified coordinates (x3,y3), using the specified points (x1,y1) and (x2,y2) as Bézier control points.通过使用指定点 (x1,y1) 和 (x2,y2) 绘制一条与当前坐标和指定坐标 (x3,y3) 相交的贝塞尔曲线,向路径添加由三个新点定义的曲线段作为贝塞尔控制点。 All coordinates are specified in double precision.所有坐标均以双精度指定。

Okay, let's be fair, that takes a little bit of reading to understand, which is probably better addressed with some graphics.好吧,让我们公平一点,这需要一点阅读才能理解,用一些图形可能会更好地解决这一问题。

The basic concept is, you have three control points, one of which is acting as a "look at" constraint.基本概念是,您有三个控制点,其中一个用作“查看”约束。

Let's assume you have three points, anchor , target and click .假设您有三个点, anchortargetclick anchor is the first point, target is the point dragged to and click is the point which was clicked AFTER the drag operation completed. anchor是第一个点, target是拖动到的点, click是拖动操作完成后click的点。

If we use the order anchor, target, click , we end up with a curve looking something like如果我们使用 order anchor, target, click ,我们最终会得到一条看起来像的曲线

曲线

where P1 == anchor , P2 == target and P3 == click .其中P1 == anchorP2 == targetP3 == click As you can see, the P2 is acting as the "look at constraint" and is trying to pull the resulting curve towards it.如您所见, P2充当“观察约束”并试图将结果曲线拉向它。

However, if, instead, we use anchor, click, target , we end up within something more like...但是,如果相反,我们使用anchor, click, target ,我们最终会得到更像...

曲线

where P1 == anchor , P2 == click and P3 == target .其中P1 == anchorP2 == clickP3 == target As you can see, the P2 is acting as the "look at constraint" and is trying to pull the resulting curve towards it.如您所见, P2充当“观察约束”并试图将结果曲线拉向它。

This is essentially how a Bézier curve works这基本上是贝塞尔曲线的工作原理

Example...例子...

Okay, so to put it all together, I wrote some test code, which you can use to change the parameter and test the idea好的,总而言之,我写了一些测试代码,您可以使用它来更改参数并测试想法

One thing this example does is it paints a "fake" example of the intended curve as the mouse is moved, after the first two points are established, giving you some visual feed back of what the curve will look like, until the user clicks the mouse and the path is set这个例子做的一件事是,当鼠标移动时,它绘制一个预期曲线的“假”例子,在建立前两个点之后,给你一些关于曲线外观的视觉反馈,直到用户点击鼠标并设置路径

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.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

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

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

    public class TestPane extends JPanel {

        private boolean dragging = false;

        private Point anchor;
        private Point target;

        private Shape fakePath;

        private List<Shape> shapes = new ArrayList<>(25);

        public TestPane() {
            addMouseMotionListener(new MouseAdapter() {
                @Override
                public void mouseDragged(MouseEvent e) {
                    dragging = true;
                    target = new Point(e.getPoint());
                    repaint();
                }

                @Override
                public void mouseMoved(MouseEvent e) {
                    if (target != null && anchor != null) {
                        fakePath = makePath(anchor, e.getPoint(), target);
                        repaint();
                    }
                }

            });

            addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    if (anchor == null) {
                        target = null;
                        anchor = new Point(e.getPoint());
                    }
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    dragging = false;
                }

                @Override
                public void mouseClicked(MouseEvent e) {
                    if (anchor != null && target != null) {
                        fakePath = null;

                        shapes.add(makePath(anchor, e.getPoint(), target));

                        anchor = null;
                        target = null;

                        repaint();
                    }
                }
            });
        }

        protected Path2D makePath(Point p1, Point p2, Point p3) {
            Path2D p = new GeneralPath();
            p.moveTo(p1.getX(), p1.getY());
            p.curveTo(p1.getX(), p1.getY(),
                            p2.getX(), p2.getY(),
                            p3.getX(), p3.getY());

            return p;
        }

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

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
            g2d.setColor(Color.BLACK);
            for (Shape shape : shapes) {
                g2d.draw(shape);
            }
            if (anchor != null && target != null) {
                g2d.setColor(Color.GREEN);
                g2d.draw(new Line2D.Double(anchor, target));
            }
            if (fakePath != null) {
                g2d.setColor(Color.BLUE);
                g2d.draw(fakePath);
            }
            g2d.dispose();
        }

    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM