<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    TWaver - 專注UI技術(shù)

    http://twaver.servasoft.com/
    posts - 171, comments - 191, trackbacks - 0, articles - 2
      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    用Swing定制流動(dòng)的Link樣式

    Posted on 2012-07-27 16:52 TWaver 閱讀(1280) 評(píng)論(1)  編輯  收藏
    想想Java2D中給我們提供的線的樣式著實(shí)很少,除了直線,虛線,好像就沒有其他的什么樣式了,如果細(xì)心的童鞋還會(huì)發(fā)現(xiàn),TWaver中倒是提供了一種比較特殊的連線,波浪曲折式的連線。

    這種波浪曲折的連線如果讓我們自己來實(shí)現(xiàn)也是有多種實(shí)現(xiàn)的方式,還記得之前幾篇文章中定制過的LinkUI么,也是各式各樣的方式,比如:

    五彩斑斕的Link



    流動(dòng)點(diǎn)式的Link


    今天給大家介紹的是箭頭流動(dòng)式的Link,何為箭頭流動(dòng),我們就先來看看效果圖:

    這是一個(gè)從from節(jié)點(diǎn)流向to節(jié)點(diǎn)的連線,連線是以一個(gè)一個(gè)箭頭組建而成,這樣的連線方式看上去比傳統(tǒng)的那種流動(dòng)漂亮多了,也有不少客戶提及到這種樣式。本篇我將詳細(xì)給大家講解一下實(shí)現(xiàn)的細(xì)節(jié)。

    首先需要定制一個(gè)ArrowLink繼承于Link,在ArrowLink中需要給它定義幾個(gè)變量,例如:線的寬度、顏色、每段箭頭的長(zhǎng)度、需要填充的流動(dòng)箭頭的數(shù)量、透明度、是否是從from流向to以及偏移(用于顯示流動(dòng))等等。 不說這么多了,直接看代碼:

     1 public class ArrowLink extends Link {
     2 
     3     public ArrowLink() {
     4         super();
     5         init();
     6     }
     7 
     8     public ArrowLink(Object id) {
     9         super(id);
    10         init();
    11     }
    12 
    13     public ArrowLink(Node from, Node to) {
    14         super(from, to);
    15         init();
    16     }
    17 
    18     public ArrowLink(Object id, Node from, Node to) {
    19         super(id, from, to);
    20         init();
    21     }
    22 
    23     private void init() {
    24         this.putLinkColor(new Color(0, 0, 0, 0));
    25         this.putLinkOutlineWidth(0);
    26         this.setLinkType(TWaverConst.LINK_TYPE_PARALLEL);
    27         this.putLinkAntialias(true);
    28         this.putClientProperty("lineWidth", 3.0f);
    29         this.putClientProperty("lineColor", Color.blue);
    30         this.putClientProperty("offset", 0.0);
    31         this.putClientProperty("segmentLength", 8.0);
    32         this.putClientProperty("fillSegmentCount", 5);
    33         this.putClientProperty("defaultAlpha", 0.2);
    34         this.putClientProperty("from", true);
    35     }
    36 
    37     public String getUIClassID() {
    38            return ArrowLinkUI.class.getName();
    39         }
    40 
    41 }

    定制完連線之后,最主要的是需要重畫LinkUI,自定義ArrowLinkUI類繼承于LinkUI并重載paintBody方法,paintBody中我們需要畫出一個(gè)一個(gè)的箭頭,箭頭實(shí)現(xiàn)起來其實(shí)還是比較簡(jiǎn)單的,我們能獲取Link的長(zhǎng)度并且知道Link上每段的長(zhǎng)度,就可以計(jì)算出需要繪制箭頭的數(shù)量。

    1 int count = (int)(length/segmentLength);

    根據(jù)箭頭的數(shù)量可以獲取到需要繪制箭頭的每個(gè)點(diǎn)的位置:

    1 List points = TWaverUtil.divideShape(this.path, count);

    獲取到這個(gè)位置之后,我們就可以以這個(gè)點(diǎn)為中心點(diǎn),分別計(jì)算出箭頭的其他兩個(gè)點(diǎn)的位置:

    1 Point2D p0 = new Point.Double();
    2 transform.transform(point, p0);
    3 Point2D p1 =  new Point.Double();
    4 transform.transform(new Point.Double(point.getX() + segmentLength/2 * sign, point.getY() - segmentLength/2), p1);
    5 Point2D p2 =  new Point.Double();
    6 transform.transform(new Point.Double(point.getX() + segmentLength/2 * sign, point.getY() + segmentLength/2), p2);

    這樣一個(gè)箭頭就可以繪制出來了

    其他的箭頭也可以以同樣方式循環(huán)繪制出來,需要注意的是箭頭是需要隨著node的位置旋轉(zhuǎn)的,因此我們需要計(jì)算出箭頭旋轉(zhuǎn)的角度和旋轉(zhuǎn)點(diǎn)的位置:

    1 AffineTransform transform = new AffineTransform();
    2 transform.translate(point.getX(), point.getY());
    3 transform.rotate(angle);
    4 transform.translate(-point.getX(), -point.getY());

    最后還有流動(dòng)的效果,這里我們?cè)O(shè)置了一個(gè)offset的參數(shù),可以表示流動(dòng)的偏移量,根據(jù)偏移量以及填充的流動(dòng)箭頭的數(shù)量來確定當(dāng)前這個(gè)箭頭的透明度:

    1 double alpha = (Double)this.element.getClientProperty("defaultAlpha");
    2 if(offset * count >= i && offset * count - fillSegmentCount <= i){
    3     alpha = 1 - (offset * count - i)/fillSegmentCount * 0.5;
    4 }

    完整繪制箭頭的代碼如下:

     1 public class ArrowLinkUI extends LinkUI {
     2 
     3     public ArrowLinkUI(TNetwork network, Link link) {
     4         super(network, link);
     5     }
     6 
     7     public void paintBody(Graphics2D g2d) {
     8         super.paintBody(g2d);
     9         this.drawFlowing(g2d);
    10     }
    11 
    12     private void drawFlowing(Graphics2D g2d) {
    13         double length = TWaverUtil.getLength(this.path);
    14         if(length < =0 ){
    15             return;
    16         }
    17 
    18         double segmentLength = (Double)this.element.getClientProperty("segmentLength");
    19         int count = (int)(length/segmentLength);
    20         List points = TWaverUtil.divideShape(this.path, count);
    21         if(points.size() < 2){
    22             return;
    23         }
    24         int fillSegmentCount = (Integer)this.element.getClientProperty("fillSegmentCount");
    25         double offset = (Double)this.element.getClientProperty("offset");
    26         Color lineColor = (Color)this.element.getClientProperty("lineColor");
    27         boolean from = (Boolean)this.element.getClientProperty("from");
    28         boolean fromLeft = this.getFromPoint().x <= this.getToPoint().x;
    29 
    30         g2d.setStroke(new BasicStroke((Float)this.element.getClientProperty("lineWidth")));
    31         for(int i=0; i
    32             Point2D point = (Point2D)points.get(i);
    33             Point2D point1, point2;
    34             double angle = 0;
    35             if(i == points.size()-1){
    36                 point1 = (Point2D)points.get(i-1);
    37                 point2 = point;
    38             } else {
    39                 point1 = point;
    40                 point2 = (Point2D)points.get(i+1);
    41             }
    42             angle = getAngle(point1, point2);
    43             int sign = (fromLeft && from || !fromLeft && !from) ? -1 : 1;
    44             if(angle == -Math.PI/2){
    45                 sign = point2.getY() > point1.getY() ? 1 : -1;
    46             }else if(angle == Math.PI/2){
    47                 sign = point2.getY() > point1.getY() ? -1 : 1;
    48             }
    49             double alpha = (Double)this.element.getClientProperty("defaultAlpha");
    50             if(offset * count >= i && offset * count - fillSegmentCount < = i){
    51                 alpha = 1 - (offset * count - i)/fillSegmentCount * 0.5;
    52             }
    53             g2d.setColor(new Color(lineColor.getRed(), lineColor.getGreen(), lineColor.getBlue(), (int)(255 * alpha)));
    54 
    55             AffineTransform transform = new AffineTransform();
    56             transform.translate(point.getX(), point.getY());
    57             transform.rotate(angle);
    58             transform.translate(-point.getX(), -point.getY());
    59 
    60             Point2D p0 = new Point.Double();
    61             transform.transform(point, p0);
    62             Point2D p1 =  new Point.Double();
    63             transform.transform(new Point.Double(point.getX() + segmentLength/2 * sign, point.getY() - segmentLength/2), p1);
    64             Point2D p2 =  new Point.Double();
    65             transform.transform(new Point.Double(point.getX() + segmentLength/2 * sign, point.getY() + segmentLength/2), p2);
    66             GeneralPath path = new GeneralPath();
    67             path.moveTo(p1.getX(), p1.getY());
    68             path.lineTo(p0.getX(), p0.getY());
    69             path.lineTo(p2.getX(), p2.getY());
    70             g2d.draw(path);
    71         }
    72     }
    73 
    74     private static double getAngle(Point2D p1, Point2D p2) {
    75         if(p1.getX() == p2.getX()){
    76             if(p2.getY() == p1.getY()){
    77                 return 0;
    78             }
    79             else if(p2.getY() > p1.getY()){
    80                 return Math.PI/2;
    81             }
    82             else{
    83                 return -Math.PI/2;
    84             }
    85         }
    86         return Math.atan((p2.getY() - p1.getY()) / (p2.getX() - p1.getX()));
    87     }
    88 }

    有了這種流動(dòng)式的箭頭,我們就可以繪制出更多豐富多彩的界面,最后給出一個(gè)完整的例子供大伙學(xué)習(xí)參考:
    注:附件中還給出了另一種Link的實(shí)現(xiàn)效果。 見原文最下方

    評(píng)論

    # re: 用Swing定制流動(dòng)的Link樣式[未登錄]  回復(fù)  更多評(píng)論   

    2015-05-28 22:16 by Neo
    如何設(shè)置Link的寬度呢?我的這個(gè)Link是連接兩個(gè)Group的。

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 成人免费观看男女羞羞视频| 全黄a免费一级毛片人人爱| 黑人粗长大战亚洲女2021国产精品成人免费视频 | 免费在线看黄网站| 免费播放美女一级毛片| 亚洲人成电影在线观看青青| 亚洲国产精品成人久久| 亚洲av无码成人精品区在线播放 | 国产日产亚洲系列最新| 成年美女黄网站18禁免费 | 五月天网站亚洲小说| 免费成人黄色大片| 女人18一级毛片免费观看| 在线观看永久免费| 日韩中文字幕免费视频| 巨胸喷奶水视频www免费视频| 黄页网址大全免费观看12网站| 亚洲成a人片在线观看天堂无码| 亚洲国产综合第一精品小说| 亚洲男人第一av网站| 亚洲高清国产AV拍精品青青草原| 亚洲免费在线观看| 亚洲AⅤ视频一区二区三区| 免费的涩涩视频在线播放| 毛片免费视频观看| 永久免费毛片在线播放| 99久久99这里只有免费费精品| 99re免费99re在线视频手机版| 免费91最新地址永久入口 | 亚洲国产精品尤物YW在线观看| 免费国产成人午夜私人影视| 又爽又高潮的BB视频免费看 | 一级做a爰片久久毛片免费陪 | 一级做a爰片性色毛片免费网站| 日韩精品视频在线观看免费| 精品国产亚洲一区二区三区在线观看 | 国产成人亚洲精品蜜芽影院| 亚洲AV成人无码久久WWW| 亚洲av日韩综合一区二区三区| 亚洲AV无码AV日韩AV网站| 久久精品国产亚洲av天美18|