日期:2014-05-17 浏览次数:21385 次
import javax.swing.*;
import java.awt.*;<p>/**
* 在两个Swing控件之间画箭头
* @author <a:href = "mailto:seth_yang@21cn.com">seth yang</a>
*/
public class Arrow {
/** 源控件,即箭头的出发控件 */
private JComponent source;
/** 目标控件,即箭头的指向控件 */
private JComponent target;
/** 箭头中间的文本,通常是该箭头标识的关系的名称 */
private String name = "";
/** 源控件关联出去的字段 */
private String sourceField = "";
/** 目标控件的关联字段 */
private String targetField = "";
/** 箭头扇形的开始角度 */
private int startAngle = 0;<p> /** 箭头扇形的半径 */
private static final int ARROW_HEIGHT = 20;
/** 箭头扇形的角度 */
private static final int ARROW_ANGLE = 30;<p> public Arrow (JComponent source, JComponent target) {
this (source.getName () + "_" + target.getName (), source, target);
}
/**
* 构造函数
*
* 创建指定名称,源控件和目标控件的箭头
* @param name 箭头的名称
* @param source 箭头的出发控件
* @param target 箭头的指向控件
*/
public Arrow (String name, JComponent source, JComponent target) {
this (name, source, target, source.getName (), target.getName ());
}<p> /**
* 构造函数
*
* 创建指定名称,源控件和目标控件的箭头
* @param name 箭头的名称
* @param source 箭头的出发控件
* @param target 箭头的指向控件
* @param sourceField 箭头的出发字段
* @param targetField 箭头的指向字段
*/
public Arrow (String name, JComponent source, JComponent target, String sourceField, String targetField) {
setName (name);
setSource (source);
setTarget (target);
this.setSourceField (sourceField);
this.setTargetField (targetField);
}<p> private Point getCenter (JComponent c) {
int x = c.getLocation ().x;
int y = c.getLocation ().y;
int w = c.getSize ().width;
int h = c.getSize ().height;<p> return new Point (x + w / 2, y + h / 2);
}<p> public void draw (Graphics g) {
g.setColor (Color.black);
Point ps = getClosestPoint (getTarget (), getSource ());
Point pt = getClosestPoint (getSource (), getTarget ());
// 画线
g.drawLine (ps.x, ps.y, pt.x, pt.y);<p> // 画箭头
// 简单起见,在这里从线段终点填充一个30度的扇形
if (ps.x != pt.x && ps.y != pt.y) {
double k = getK (ps, pt);
if (ps.x > pt.x)
startAngle = 360 - (int) (Math.atan (k) * 180 / Math.PI) - 15;
else
startAngle = 180 - (int) (Math.atan (k) * 180 / Math.PI) - 15;
}
// 圆心
Point pc = new Point (pt.x - ARROW_HEIGHT, pt.y - ARROW_HEIGHT);
g.fillArc (pc.x, pc.y, 2 * ARROW_HEIGHT, 2 * ARROW_HEIGHT, startAngle, ARROW_ANGLE);<p> FontMetrics fm = g.getFontMetrics ();
int ascent = fm.getAscent ();
int descent = fm.getDescent ();<p> // 在线条中心点处显示名称
int mx = (ps.x + pt.x) / 2;
int my = (ps.y + pt.y) / 2;
g.drawString (name, mx, my + ascent);<p> if (sourceField == null) sourceField = "";
if (targetField == null) targetField = "";<p> if (ps.y < pt.y) {// 源在目标上方,目标文字应该在更上面一些,源文字应该更下面一些
// 在箭头处显示目标
if (ps.x > pt.x) // 目标在源的左方
g.drawString (getTargetField (), pt.x - fm.stringWidth (getTargetField ()), pt.