绘制箭头时 , 先设置一条直线的起始点和终止点 , 箭头绘制在该线段上 ;
/**
* 起始点 X, Y 坐标
* 终止点 X, Y 坐标
*/
private int startX, startY, endX, endY;
为箭头指定一个长度 , 该长度的末尾是 箭头终点 , 在直线上确定箭头终点 , 该终点延伸出两个尾翼 , 尾翼也指定一个长度 ;
/**
* 箭头 左右两个尾翼 长度
*/
private int arrowWingLength = 20;
/**
* 箭头终点在直线的位置
*/
private float arrowEndRatio = 0.5F;
/**
* 箭头长度
*/
private int arrowLength;
先把箭头附着的直线 , 绘制出来 ;
// 绘制直线
g.drawLine(startX, startY, endX, endY);
首先 , 确定起始点和终止点 , 在 x , y 轴上的差值 ;
// 计算起始点和终止点在 x, y 方向的差值
int deltaX = endX - startX;
int deltaY = endY - startY;
然后 , 计算出起始点到终止点的角度 , deltaY / deltaX 是该角度的正切 , 已知正切值 , 计算角度 , 使用 Math.atan2 函数即可 , 最终计算的角度是 该直线 与 x 轴夹角 ;
// 计算 直线的角度
double angle = Math.atan2(deltaY, deltaX);
再后 , 使用勾股定理计算直线的长度 ;
// 计算直线的长度
int len = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
再后 , 根据比例计算出箭头的长度 , 根据该长度 , 确定箭头终点的坐标 ; 下图中蓝色的箭头 , 就是计算出的箭头尾部相对于起始点的增量 ;
// 设置箭头终点在直线的位置 , 根据比例计算出箭头长度
arrowLength = (int) (len * arrowEndRatio);
// 箭头终点坐标
int arrowEndX = (int) (startX + arrowLength * Math.cos(angle));
int arrowEndY = (int) (startY + arrowLength * Math.sin(angle));
最后 , 绘制箭头的两个尾翼 , 箭头的位置 ; 尾翼的起始点 arrowEndX, arrowEndY , 终止点需要根据角度计算出来 ;
// 绘制箭头 尾翼 线段 , 直线的角度 增减 45 度 , 即可获得尾翼的角度
g.drawLine(arrowEndX, arrowEndY, (int) (arrowEndX - arrowWingLength * Math.cos(angle + Math.PI / 4)), (int) (arrowEndY - arrowWingLength * Math.sin(angle + Math.PI / 4)));
g.drawLine(arrowEndX, arrowEndY, (int) (arrowEndX - arrowWingLength * Math.cos(angle - Math.PI / 4)), (int) (arrowEndY - arrowWingLength * Math.sin(angle - Math.PI / 4)));
完整代码示例 :
// 绘制箭头
private void drawArrow(Graphics g, int startX, int startY, int endX, int endY) {
// 计算起始点和终止点在 x, y 方向的差值
int deltaX = endX - startX;
int deltaY = endY - startY;
// 计算 直线的角度
double angle = Math.atan2(deltaY, deltaX);
// 计算直线的长度
int len = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// 设置箭头终点在直线的位置 , 根据比例计算出箭头长度
arrowLength = (int) (len * arrowEndRatio);
// 箭头终点坐标
int arrowEndX = (int) (endX - arrowLength * Math.cos(angle));
int arrowEndY = (int) (endY - arrowLength * Math.sin(angle));
// 绘制箭头 尾翼 线段 , 直线的角度 增减 45 度 , 即可获得尾翼的角度
g.drawLine(arrowEndX, arrowEndY, (int) (arrowEndX - arrowWingLength * Math.cos(angle + Math.PI / 4)), (int) (arrowEndY - arrowWingLength * Math.sin(angle + Math.PI / 4)));
g.drawLine(arrowEndX, arrowEndY, (int) (arrowEndX - arrowWingLength * Math.cos(angle - Math.PI / 4)), (int) (arrowEndY - arrowWingLength * Math.sin(angle - Math.PI / 4)));
}
代码示例 :
import java.awt.*;
public class ArrowCanvas extends Canvas {
/**
* 起始点 X, Y 坐标
* 终止点 X, Y 坐标
*/
private int startX, startY, endX, endY;
/**
* 箭头 左右两个尾翼 长度
*/
private int arrowWingLength = 20;
/**
* 箭头终点在直线的位置
*/
private float arrowEndRatio = 0.5F;
/**
* 箭头长度
*/
private int arrowLength;
public ArrowCanvas(int startX, int startY, int endX, int endY) {
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
// 设置画布大小
setSize(400, 400);
}
public void paint(Graphics g) {
// 绘制直线
g.drawLine(startX, startY, endX, endY);
// 绘制箭头
drawArrow(g, startX, startY, endX, endY);
}
// 绘制箭头
private void drawArrow(Graphics g, int startX, int startY, int endX, int endY) {
// 计算起始点和终止点在 x, y 方向的差值
int deltaX = endX - startX;
int deltaY = endY - startY;
// 计算 直线的角度
// 返回的是 这条直线 与 x 轴的夹角
// deltaY / deltaX 是该角度的正切
// 已知正切值 , 计算角度 , 使用 Math.atan2 函数即可
// 最终计算的角度是 该直线 与 x 轴夹角
double angle = Math.atan2(deltaY, deltaX);
// 计算直线的长度
int len = (int) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// 设置箭头终点在直线的位置 , 根据比例计算出箭头长度
arrowLength = (int) (len * arrowEndRatio);
// 箭头终点坐标
int arrowEndX = (int) (startX + arrowLength * Math.cos(angle));
int arrowEndY = (int) (startY + arrowLength * Math.sin(angle));
// 绘制箭头 尾翼 线段 , 直线的角度 增减 45 度 , 即可获得尾翼的角度
g.drawLine(arrowEndX, arrowEndY, (int) (arrowEndX - arrowWingLength * Math.cos(angle + Math.PI / 4)), (int) (arrowEndY - arrowWingLength * Math.sin(angle + Math.PI / 4)));
g.drawLine(arrowEndX, arrowEndY, (int) (arrowEndX - arrowWingLength * Math.cos(angle - Math.PI / 4)), (int) (arrowEndY - arrowWingLength * Math.sin(angle - Math.PI / 4)));
}
public static void main(String[] args) {
// 创建窗口并添加 ArrowCanvas 组件
Frame f = new Frame("ArrowCanvas Example");
ArrowCanvas ac = new ArrowCanvas(50, 50, 200, 200);
f.add(ac);
// 设置窗口大小并可见
f.setSize(400, 400);
f.setVisible(true);
}
}
执行结果 :