Java Swing繪製箭頭

Java Swing繪製箭頭

繪製單向箭頭、雙向箭頭

 

package com.xiangqian.swing;

import javax.swing.*;
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;

/**
 * 繪製箭頭
 *
 * @author xiangqian
 * @date 16:00 2019/10/31
 */
public class DrawArrow {

    /**
     * 繪製面板
     *
     * @author xiangqian
     * @date 15:38 2019/11/03
     */
    public static class DrawPanel extends JPanel {

        private BasicStroke lineStroke;

        public DrawPanel() {
            lineStroke = new BasicStroke(2.0f);
        }

        @Override
        protected void paintComponent(Graphics g) {
            draw((Graphics2D) g);
        }

        /**
         * 繪製
         *
         * @param g2d
         */
        private void draw(Graphics2D g2d) {

            Line2D.Double line2D = null;
            Arrow.Attributes arrowAttributes = null;

            // 繪製線的“方向1”箭頭
            line2D = new Line2D.Double(120, 100, 300, 300);
            arrowAttributes = new Arrow.Attributes();
            drawLineArrowDirection1(g2d, arrowAttributes, line2D);

            // 繪製線的“方向2”箭頭
            line2D = new Line2D.Double(110, 330, 300, 330);
            arrowAttributes = new Arrow.Attributes();
            arrowAttributes.angle = 45;
            arrowAttributes.height = 80;
            drawLineArrowDirection2(g2d, arrowAttributes, line2D);

            // 繪製線的“雙向”箭頭
            line2D = new Line2D.Double(500, 200, 260, 200);
            arrowAttributes = new Arrow.Attributes();
            arrowAttributes.angle = 30;
            arrowAttributes.height = 40;
            drawLineArrowDirectionAll(g2d, arrowAttributes, line2D);
        }


        /**
         * 繪製線的“方向1”箭頭
         *
         * @param g2d
         * @param arrowAttributes 箭頭屬性
         * @param line2D          線
         */
        private void drawLineArrowDirection1(Graphics2D g2d, Arrow.Attributes arrowAttributes, Line2D.Double line2D) {
            drawLine(g2d, line2D);
            drawArrow(g2d, arrowAttributes, line2D.getP1(), line2D.getP2());
        }

        /**
         * 繪製線的“方向2”箭頭
         *
         * @param g2d
         * @param arrowAttributes 箭頭屬性
         * @param line2D          線
         */
        private void drawLineArrowDirection2(Graphics2D g2d, Arrow.Attributes arrowAttributes, Line2D.Double line2D) {
            drawLine(g2d, line2D);
            drawArrow(g2d, arrowAttributes, line2D.getP2(), line2D.getP1());
        }

        /**
         * 繪製線的“雙向”箭頭
         *
         * @param g2d
         * @param arrowAttributes 箭頭屬性
         * @param line2D          線
         */
        private void drawLineArrowDirectionAll(Graphics2D g2d, Arrow.Attributes arrowAttributes, Line2D.Double line2D) {
            drawLine(g2d, line2D);
            drawArrow(g2d, arrowAttributes, line2D.getP1(), line2D.getP2());
            drawArrow(g2d, arrowAttributes, line2D.getP2(), line2D.getP1());
        }

        /**
         * 繪製線
         *
         * @param g2d
         * @param line2D
         */
        private void drawLine(Graphics2D g2d, Line2D.Double line2D) {
            g2d.setColor(Color.BLACK);
            g2d.setStroke(lineStroke);
            g2d.draw(line2D);
        }

        /**
         * 繪製箭頭
         *
         * @param g2d
         * @param arrowAttributes 箭頭屬性
         * @param point1          線的第一個點
         * @param point2          線的第二個點
         */
        private void drawArrow(Graphics2D g2d, Arrow.Attributes arrowAttributes, Point2D point1, Point2D point2) {
            // 獲取Arrow實例
            Arrow arrow = getArrow(arrowAttributes, point1, point2);

            // 構建GeneralPath
            GeneralPath arrow2D = new GeneralPath();
            arrow2D.moveTo(arrow.point1.x, arrow.point1.y);
            arrow2D.lineTo(arrow.point2.x, arrow.point2.y);
            arrow2D.lineTo(arrow.point3.x, arrow.point3.y);
            arrow2D.closePath();

            // 繪製
            g2d.setColor(arrow.attributes.color);
            g2d.fill(arrow2D);
        }

        /**
         * 獲取箭頭實體類
         *
         * @param arrowAttributes 箭頭屬性
         * @param point1          線的第一個點
         * @param point2          線的第二個點
         * @return
         */
        private Arrow getArrow(Arrow.Attributes arrowAttributes, Point2D point1, Point2D point2) {
            Arrow arrow = new Arrow(arrowAttributes);

            // 計算斜邊
            double hypotenuse = arrow.attributes.height / Math.cos(Math.toRadians(arrow.attributes.angle / 2));

            // 計算當前線所在的象限
            int quadrant = -1;
            if (point1.getX() > point2.getX() && point1.getY() < point2.getY()) {
                quadrant = 1;
            } else if (point1.getX() < point2.getX() && point1.getY() < point2.getY()) {
                quadrant = 2;
            } else if (point1.getX() < point2.getX() && point1.getY() > point2.getY()) {
                quadrant = 3;
            } else if (point1.getX() > point2.getX() && point1.getY() > point2.getY()) {
                quadrant = 4;
            }

            // 計算線的夾角
            double linAngle = getLineAngle(point1.getX(), point1.getY(), point2.getX(), point2.getY());
            if (Double.isNaN(linAngle)) {
                // 線與x軸垂直
                if (point1.getX() == point2.getX()) {
                    if (point1.getY() < point2.getY()) {
                        linAngle = 90;
                    } else {
                        linAngle = 270;
                    }
                    quadrant = 2;
                }
            }
            // 線與y軸垂直
            else if (linAngle == 0) {
                if (point1.getY() == point2.getY()) {
                    if (point1.getX() < point2.getX()) {
                        linAngle = 0;
                    } else {
                        linAngle = 180;
                    }
                    quadrant = 2;
                }
            }

            // 上側一半箭頭
            double xAngle = linAngle - arrow.attributes.angle / 2; // 與x軸夾角
            double py0 = hypotenuse * Math.sin(Math.toRadians(xAngle)); // 計算y方向增量
            double px0 = hypotenuse * Math.cos(Math.toRadians(xAngle)); // 計算x方向增量

            // 下側一半箭頭
            double yAngle = 90 - linAngle - arrow.attributes.angle / 2; // 與y軸夾角
            double px1 = hypotenuse * Math.sin(Math.toRadians(yAngle));
            double py1 = hypotenuse * Math.cos(Math.toRadians(yAngle));

            // 第一象限
            if (quadrant == 1) {
                px0 = -px0;
                px1 = -px1;

            } else if (quadrant == 2) {
                // do nothing
            } else if (quadrant == 3) {
                py0 = -py0;
                py1 = -py1;

            } else if (quadrant == 4) {
                py0 = -py0;
                px0 = -px0;

                px1 = -px1;
                py1 = -py1;
            }

            // build
            arrow.point1 = new Point2D.Double();
            arrow.point1.x = point1.getX();
            arrow.point1.y = point1.getY();

            arrow.point2 = new Point2D.Double();
            arrow.point2.x = point1.getX() + px0;
            arrow.point2.y = point1.getY() + py0;

            arrow.point3 = new Point2D.Double();
            arrow.point3.x = point1.getX() + px1;
            arrow.point3.y = point1.getY() + py1;

            return arrow;
        }

        /**
         * 獲取線與X軸的夾角
         *
         * @param x1
         * @param y1
         * @param x2
         * @param y2
         * @return
         */
        protected double getLineAngle(double x1, double y1, double x2, double y2) {
            double k1 = (y2 - y1) / (x2 - x1);
            double k2 = 0;
            return Math.abs(Math.toDegrees(Math.atan((k2 - k1) / (1 + k1 * k2))));
        }
    }


    /**
     * 箭頭實體類
     *
     * @author xiangqian
     * @date 16:06 2019/10/31
     */
    public static class Arrow {
        Attributes attributes;
        Point2D.Double point1;
        Point2D.Double point2;
        Point2D.Double point3;

        public Arrow(Attributes attributes) {
            this.attributes = attributes;
        }

        /**
         * 箭頭屬性
         *
         * @author xiangqian
         * @date 15:41 2019/11/03
         */
        public static class Attributes {
            double height; // 箭頭的高度
            double angle; // 箭頭角度
            Color color; // 箭頭顏色

            public Attributes() {
                this.height = 60;
                this.angle = 30;
                this.color = Color.BLACK;
            }
        }
    }


    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setTitle("繪製箭頭");
        Dimension dimension = new Dimension(800, 600);
        frame.setSize(dimension);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(new DrawPanel());
        frame.setVisible(true);
    }

}

效果展示

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章