如何在Java中绘制有向箭头线?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2027613/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to draw a directed arrow line in Java?
提问by Yatendra Goel
I want to draw a directed arrow line through Java.
我想通过Java绘制一条有向箭头线。
At present, I am using java.awt.Line2D.Double
class to draw a line
目前,我正在使用java.awt.Line2D.Double
类来画一条线
g2.setStroke(new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); // g2 is an instance of Graphics2D
g2.draw(new Line2D.Double(x1,y1,x2,y2));
But only the line appears and no directed arrow appears. BasicStroke.Join_BEVEL
is used to draw a directed arrow. It is applied when two line segments meet.
但只出现线,没有出现有向箭头。 BasicStroke.Join_BEVEL
用于绘制有向箭头。当两条线段相遇时应用它。
The line I am drawing meets the border of a rectangle but no directed arrow is drawn. Only a simple line is drawn.
我正在绘制的线与矩形的边界相交,但没有绘制有向箭头。只画了一条简单的线。
Is there anything I am missing?
有什么我想念的吗?
采纳答案by Pete Kirkham
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 ).
如果折线成特定角度,则在折线中的线段之间绘制斜面。如果您正在绘制一条线,而该线恰好是在具有某种颜色的其他一些像素附近绘制的,则它没有任何意义 - 一旦您绘制了矩形,Graphics 对象就不知道该矩形,它(实际上)只保存像素。(或者更确切地说,图像或操作系统窗口包含像素)。
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.
要绘制一个简单的箭头,请在执行过程中为茎绘制一条线,然后为 V 形绘制一条折线。更好看更好的箭头有弯曲的侧面并被填充。
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 ) );
}
}
}
回答by Vicente Reig
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.
尽管 Pete 的帖子非常全面,但我使用这种方法绘制了一条非常简单的线,其末端有一个小三角形。
// 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();
}
回答by Michael Zlatkovsky - Microsoft
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);
过去,我编写了以下方法来创建一个箭头形状,然后我可以用 ((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));
}
回答by phibao37
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);
}
回答by mhamad arsalan
Just in case if you want an non-programmaticarrow (I.e. for text purpose) in Fastway, 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.
以防万一,如果您想要一个非编程箭头(即用于文本目的)以快速方式,您可以使用<html>
代码将箭头制作为文本,只需将您的 HTML 代码放在.setText()
组件的方法中。我有java 1.8u202
它工作正常。
myLabel.setText("<html><body>←</body></html>");
myLabel.setText("<html><body>←</body></html>");
this code
←
is for left-pointing arrow
此代码
←
用于向左箭头
other arrow directions HTML code from This Website
来自本网站的其他箭头方向 HTML 代码