How to draw a directed arrow line in Java?

后端 未结 5 1655
眼角桃花
眼角桃花 2020-12-01 06:43

I want to draw a directed arrow line through Java.

At present, I am using java.awt.Line2D.Double class to draw a line

g2.setStroke(new B         


        
相关标签:
5条回答
  • 2020-12-01 07:04

    Just in case if you want an non-programmatic arrow (I.e. for text purpose) in Fast way, you can use <html> code for making arrow as text, just put your HTML code inside .setText() method for a component. I have java 1.8u202 it works fine.

    myLabel.setText("<html><body>&#8592;</body></html>");

    this code &#8592; is for left-pointing arrow

    other arrow directions HTML code from This Website

    0 讨论(0)
  • 2020-12-01 07:07

    In the past, I've written the following method to create an an arrow shape, which I can then fill with ((Graphics2D) g).fill(shape);

    public static Shape createArrowShape(Point fromPt, Point toPt) {
        Polygon arrowPolygon = new Polygon();
        arrowPolygon.addPoint(-6,1);
        arrowPolygon.addPoint(3,1);
        arrowPolygon.addPoint(3,3);
        arrowPolygon.addPoint(6,0);
        arrowPolygon.addPoint(3,-3);
        arrowPolygon.addPoint(3,-1);
        arrowPolygon.addPoint(-6,-1);
    
    
        Point midPoint = midpoint(fromPt, toPt);
    
        double rotate = Math.atan2(toPt.y - fromPt.y, toPt.x - fromPt.x);
    
        AffineTransform transform = new AffineTransform();
        transform.translate(midPoint.x, midPoint.y);
        double ptDistance = fromPt.distance(toPt);
        double scale = ptDistance / 12.0; // 12 because it's the length of the arrow polygon.
        transform.scale(scale, scale);
        transform.rotate(rotate);
    
        return transform.createTransformedShape(arrowPolygon);
    }
    
    private static Point midpoint(Point p1, Point p2) {
        return new Point((int)((p1.x + p2.x)/2.0), 
                         (int)((p1.y + p2.y)/2.0));
    }
    
    0 讨论(0)
  • 2020-12-01 07:12

    This is my approach, absolute Math only:

    /**
     * Draw an arrow line between two points.
     * @param g the graphics component.
     * @param x1 x-position of first point.
     * @param y1 y-position of first point.
     * @param x2 x-position of second point.
     * @param y2 y-position of second point.
     * @param d  the width of the arrow.
     * @param h  the height of the arrow.
     */
    private void drawArrowLine(Graphics g, int x1, int y1, int x2, int y2, int d, int h) {
        int dx = x2 - x1, dy = y2 - y1;
        double D = Math.sqrt(dx*dx + dy*dy);
        double xm = D - d, xn = xm, ym = h, yn = -h, x;
        double sin = dy / D, cos = dx / D;
    
        x = xm*cos - ym*sin + x1;
        ym = xm*sin + ym*cos + y1;
        xm = x;
    
        x = xn*cos - yn*sin + x1;
        yn = xn*sin + yn*cos + y1;
        xn = x;
    
        int[] xpoints = {x2, (int) xm, (int) xn};
        int[] ypoints = {y2, (int) ym, (int) yn};
    
        g.drawLine(x1, y1, x2, y2);
        g.fillPolygon(xpoints, ypoints, 3);
    }
    
    0 讨论(0)
  • 2020-12-01 07:19

    Although Pete's post is awesomely comprehensive, I'm using this method to draw a very simple line with a little triangle at its end.

    // create an AffineTransform 
    // and a triangle centered on (0,0) and pointing downward
    // somewhere outside Swing's paint loop
    AffineTransform tx = new AffineTransform();
    Line2D.Double line = new Line2D.Double(0,0,100,100);
    
    Polygon arrowHead = new Polygon();  
    arrowHead.addPoint( 0,5);
    arrowHead.addPoint( -5, -5);
    arrowHead.addPoint( 5,-5);
    
    // [...]
    private void drawArrowHead(Graphics2D g2d) {  
        tx.setToIdentity();
        double angle = Math.atan2(line.y2-line.y1, line.x2-line.x1);
        tx.translate(line.x2, line.y2);
        tx.rotate((angle-Math.PI/2d));  
    
        Graphics2D g = (Graphics2D) g2d.create();
        g.setTransform(tx);   
        g.fill(arrowHead);
        g.dispose();
    }
    
    0 讨论(0)
  • 2020-12-01 07:21

    The bevel is drawn between segments in a polyline if they are at certain angles. It has no bearing if you are drawing a line which happens to be drawn near some other pixels which are of a certain colour - once you've drawn the rectangle, the Graphics object doesn't know about the rectangle, it (in effect) only holds the pixels. ( or rather the image or OS window holds the pixels ).

    To draw a simple arrow, draw a line for the stalk as you're doing, then a polyline for the vee. Nicer looking nicer arrows have curved sides and are filled.

    You probably don't want to use bevel for the arrow head, as bevels are a flat; instead use the mitre option:

    import java.awt.*;
    import java.awt.geom.*;
    import javax.swing.*;
    
    public class BevelArrows
    {
        public static void main ( String...args )
        {
            SwingUtilities.invokeLater ( new Runnable () {
                BevelArrows arrows = new BevelArrows();
    
                @Override
                public void run () {
                    JFrame frame = new JFrame ( "Bevel Arrows" );
    
                    frame.add ( new JPanel() {
                        public void paintComponent ( Graphics g ) {
                            arrows.draw ( ( Graphics2D ) g, getWidth(), getHeight() );
                        }
                    }
                    , BorderLayout.CENTER );
    
                    frame.setSize ( 800, 400 );
                    frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
                    frame.setVisible ( true );
                }
            } );
        }
    
        interface Arrow {
            void draw ( Graphics2D g );
        }
    
        Arrow[] arrows = { new LineArrow(), new CurvedArrow() };
    
        void draw ( Graphics2D g, int width, int height )
        {
            g.setRenderingHint ( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
    
            g.setColor ( Color.WHITE );
            g.fillRect ( 0, 0, width, height );
    
            for ( Arrow arrow : arrows ) {
                g.setColor ( Color.ORANGE );
                g.fillRect ( 350, 20, 20, 280 );
    
                g.setStroke ( new BasicStroke ( 20.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL ) );
                g.translate ( 0, 60 );
                arrow.draw ( g );
    
                g.setStroke ( new BasicStroke ( 20.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER ) );
                g.translate ( 0, 100 );
                arrow.draw ( g );
    
                g.setStroke ( new BasicStroke ( 20.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND ) );
                g.translate ( 0, 100 );
                arrow.draw ( g );
    
                g.translate ( 400, -260 );
            }
        }
    
        static class LineArrow  implements Arrow
        {
            public void draw ( Graphics2D g )
            {
                // where the control point for the intersection of the V needs calculating
                // by projecting where the ends meet
    
                float arrowRatio = 0.5f;
                float arrowLength = 80.0f;
    
                BasicStroke stroke = ( BasicStroke ) g.getStroke();
    
                float endX = 350.0f;
    
                float veeX;
    
                switch ( stroke.getLineJoin() ) {
                    case BasicStroke.JOIN_BEVEL:
                        // IIRC, bevel varies system to system, this is approximate
                        veeX = endX - stroke.getLineWidth() * 0.25f;
                        break;
                    default:
                    case BasicStroke.JOIN_MITER:
                        veeX = endX - stroke.getLineWidth() * 0.5f / arrowRatio;
                        break;
                    case BasicStroke.JOIN_ROUND:
                        veeX = endX - stroke.getLineWidth() * 0.5f;
                        break;
                }
    
                // vee
                Path2D.Float path = new Path2D.Float();
    
                path.moveTo ( veeX - arrowLength, -arrowRatio*arrowLength );
                path.lineTo ( veeX, 0.0f );
                path.lineTo ( veeX - arrowLength, arrowRatio*arrowLength );
    
                g.setColor ( Color.BLUE );
                g.draw ( path );
    
                // stem for exposition only
                g.setColor ( Color.YELLOW );
                g.draw ( new Line2D.Float ( 50.0f, 0.0f, veeX, 0.0f ) );
    
                // in practice, move stem back a bit as rounding errors
                // can make it poke through the sides of the Vee
                g.setColor ( Color.RED );
                g.draw ( new Line2D.Float ( 50.0f, 0.0f, veeX - stroke.getLineWidth() * 0.25f, 0.0f ) );
            }
        }
    
        static class CurvedArrow  implements Arrow
        {
            // to draw a nice curved arrow, fill a V shape rather than stroking it with lines
            public void draw ( Graphics2D g )
            {
                // as we're filling rather than stroking, control point is at the apex,
    
                float arrowRatio = 0.5f;
                float arrowLength = 80.0f;
    
                BasicStroke stroke = ( BasicStroke ) g.getStroke();
    
                float endX = 350.0f;
    
                float veeX = endX - stroke.getLineWidth() * 0.5f / arrowRatio;
    
                // vee
                Path2D.Float path = new Path2D.Float();
    
                float waisting = 0.5f;
    
                float waistX = endX - arrowLength * 0.5f;
                float waistY = arrowRatio * arrowLength * 0.5f * waisting;
                float arrowWidth = arrowRatio * arrowLength;
    
                path.moveTo ( veeX - arrowLength, -arrowWidth );
                path.quadTo ( waistX, -waistY, endX, 0.0f );
                path.quadTo ( waistX, waistY, veeX - arrowLength, arrowWidth );
    
                // end of arrow is pinched in
                path.lineTo ( veeX - arrowLength * 0.75f, 0.0f );
                path.lineTo ( veeX - arrowLength, -arrowWidth );
    
                g.setColor ( Color.BLUE );
                g.fill ( path );
    
                // move stem back a bit
                g.setColor ( Color.RED );
                g.draw ( new Line2D.Float ( 50.0f, 0.0f, veeX - arrowLength * 0.5f, 0.0f ) );
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题