java - 如何画一条有方向、固定长度的线

标签 java swing awt

当我向它提供 2 个点和一个角度(方向)时,我希望绘制一条线直到屏幕边缘。例如,如果第一个鼠标点是 4,4,下一个鼠标点是 6,6,那么从这些点您知道该线具有东北方向,那么应该从 4,4 到终点绘制一条线屏幕并经过6,6。注意:当鼠标到达 6,6 后,当鼠标仍处于 6,6 时,应将线绘制到屏幕边缘。

enter image description here

此外,这应该在 MouseMoved 中完成,最好不要点击,这意味着两个鼠标点都是从 MouseMoved 获取的。我尝试了一整天以获得输出但没有用。

最佳答案

你需要分解你的问题......

首先,您需要能够计算两点之间的角度

double angle = Math.atan2(toY - fromY, toX - fromX);

哇,这有点简单(谢谢 Internet )

接下来,我们需要能够计算圆半径上的一个点(好吧,这可能听起来很奇怪,但这是我能想到的最简单的解决方案......我知道我可以解决它,谢谢 Internet )

toX = (int) (Math.round(fromX + (radius * Math.cos(angle))));
toY = (int) (Math.round(fromY + (radius * Math.sin(angle))));

我们要做的是,创建一个足够大的圆圈,使其扩展到可见的框架边界之外,然后画出我们的线!简单!

Follow the dots

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.event.MouseAdapter;
import java.awt.event.MouseEvent;
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 Point from;
        private Point clickTo;
        private Point to;

        public TestPane() {
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    if (to != null) {
                        to = null;
                        clickTo = null;
                        from = null;
                    }
                    if (from != null) {
                        to = e.getPoint();
                        clickTo = new Point(to);
                        double angle = Math.atan2(to.y - from.y, to.x - from.x);
                        int radius = Math.max(getWidth(), getHeight()) * 2;

                        to.x = (int) (Math.round(from.x + (radius * Math.cos(angle))));
                        to.y = (int) (Math.round(from.y + (radius * Math.sin(angle))));
                    } else {
                        from = e.getPoint();
                    }
                    repaint();
                }
            });
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            if (from != null) {
                g2d.setColor(Color.RED);
                g2d.fillOval(from.x - 4, from.y - 4, 8, 8);

                if (to != null) {
                    g2d.setColor(Color.GREEN);
                    g2d.fillOval(clickTo.x - 4, clickTo.y - 4, 8, 8);

                    g2d.setColor(Color.BLUE);
                    g2d.drawLine(from.x, from.y, to.x, to.y);
                }
            }
            g2d.dispose();
        }

    }

}

带有中心 anchor ...

MouseMotionListener支持

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.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
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 Point from;
        private Point clickTo;
        private Point to;

        public TestPane() {
            addMouseMotionListener(new MouseMotionAdapter() {
                @Override
                public void mouseMoved(MouseEvent e) {
                    from = new Point(getWidth() / 2, getHeight() / 2);
                    to = e.getPoint();
                    clickTo = new Point(to);
                    double angle = Math.atan2(to.y - from.y, to.x - from.x);
                    int radius = Math.max(getWidth(), getHeight()) * 2;

                    to.x = (int) (Math.round(from.x + (radius * Math.cos(angle))));
                    to.y = (int) (Math.round(from.y + (radius * Math.sin(angle))));
                    repaint();
                }

            });
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            if (from != null) {
                g2d.setColor(Color.RED);
                g2d.fillOval(from.x - 4, from.y - 4, 8, 8);

                if (to != null) {
                    g2d.setColor(Color.GREEN);
                    g2d.fillOval(clickTo.x - 4, clickTo.y - 4, 8, 8);

                    g2d.setColor(Color.BLUE);
                    g2d.drawLine(from.x, from.y, to.x, to.y);
                }
            }
            g2d.dispose();
        }

    }

}

One more small thing, i need the line to have a flexible length, by that i mean it should be within the screen, and since this is a rectangle then the width and height will differ, and having a fixed length will make problems because it will be long at some parts and short at others, any idea ?

因此,您需要知道线条与矩形边界的碰撞位置,这基本上可以归结为线条碰撞检测(因为矩形只有四条线)

所以,Internet to the rescue

我将这个想法进一步发展,并制作了一个方法,该方法采用 RectangleLine2D 并返回碰撞点所在的 Point2D如果没有发生碰撞,则发生或 null (在这种情况下,我们应该 99.9% 保证发生碰撞)

Shortended

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.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
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 Point from;
        private Point clickTo;
        private Point to;

        public TestPane() {
            addMouseMotionListener(new MouseMotionAdapter() {
                @Override
                public void mouseMoved(MouseEvent e) {
                    from = new Point(getWidth() / 2, getHeight() / 2);
                    to = e.getPoint();
                    clickTo = new Point(to);
                    double angle = Math.atan2(to.y - from.y, to.x - from.x);
                    int radius = Math.max(getWidth(), getHeight()) * 2;

                    to.x = (int) (Math.round(from.x + (radius * Math.cos(angle))));
                    to.y = (int) (Math.round(from.y + (radius * Math.sin(angle))));
                    repaint();
                }

            });
        }

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

        public Point2D getIntersectionPoint(Line2D line1, Line2D line2) {
            if (!line1.intersectsLine(line2)) {
                return null;
            }
            double px = line1.getX1(),
                    py = line1.getY1(),
                    rx = line1.getX2() - px,
                    ry = line1.getY2() - py;
            double qx = line2.getX1(),
                    qy = line2.getY1(),
                    sx = line2.getX2() - qx,
                    sy = line2.getY2() - qy;

            double det = sx * ry - sy * rx;
            if (det == 0) {
                return null;
            } else {
                double z = (sx * (qy - py) + sy * (px - qx)) / det;
                if (z == 0 || z == 1) {
                    return null;  // intersection at end point!
                }
                return new Point2D.Float(
                        (float) (px + z * rx), (float) (py + z * ry));
            }
        } // end intersection line-line

        public Point2D getIntersectionPoint(Line2D line, Rectangle bounds) {
            Point2D top = getIntersectionPoint(line, new Line2D.Double(bounds.x, bounds.y, bounds.x + bounds.width, bounds.y));
            Point2D bottom = getIntersectionPoint(line, new Line2D.Double(bounds.x, bounds.y + bounds.height, bounds.x + bounds.width, bounds.y + bounds.height));
            Point2D left = getIntersectionPoint(line, new Line2D.Double(bounds.x, bounds.y, bounds.x, bounds.y + bounds.height));
            Point2D right = getIntersectionPoint(line, new Line2D.Double(bounds.x + bounds.width, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height));

            return top != null ? top 
                    : bottom != null ? bottom 
                    : left != null ? left
                    : right != null ? right
                    : null;
        } 

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g.create();
            Rectangle bounds = new Rectangle(50, 50, getWidth() - 100, getHeight() - 100);
            g2d.draw(bounds);

            if (from != null) {
                g2d.setColor(Color.RED);
                g2d.fillOval(from.x - 4, from.y - 4, 8, 8);

                if (to != null) {
                    g2d.setColor(Color.GREEN);
                    g2d.fillOval(clickTo.x - 4, clickTo.y - 4, 8, 8);

                    Line2D line = new Line2D.Double(from, to);
                    g2d.setColor(Color.BLUE);
                    g2d.draw(line);

                    Point2D intersectPoint = getIntersectionPoint(line, bounds);

                    g2d.setColor(Color.MAGENTA);
                    g2d.fill(new Ellipse2D.Double(intersectPoint.getX() - 4, intersectPoint.getY() - 4, 8, 8));

                    g2d.draw(new Line2D.Double(from, intersectPoint));
                }
            }
            g2d.dispose();
        }

    }

}

因此,知道您在组件的可见边界之外有一条线的投影(这对您的其他问题很有帮助),并知道该线与内部边界感兴趣的位置

关于java - 如何画一条有方向、固定长度的线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35648983/

相关文章:

Java小程序不会移动图像

java - 调试空指针异常

java - 为 Factory 类创建的对象注入(inject) Mocks

java - 将 List<MyDataType> 转换为 List<String> 的更好方法

java - JFileChooser 打开多个txt文件

java - 使用 JColorChooser 更改 JPanel 颜色

java - 为什么JComboBox会忽略空值状态?

java - 尝试读取文件后 rrString 为空

java - Spring 3.0 MVC :Redirect without parameters being added to my url

java - 多个 JFrame 或 JDialog