日期:2014-05-17 浏览次数:21217 次
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.