TWaver - 專注UI技術

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

          如何指定Node的Label的最大寬度

          Posted on 2013-07-19 15:01 TWaver 閱讀(1913) 評論(2)  編輯  收藏
          Network 上面的Node,默認情況是Label的折行只能通過HTML的<br>標簽,這樣做的弊端就是不能動態 根據文字的長度智能折行。 如果需要達到這個要求,需要定制Node的LabelAttachment。

          最初的想法是 創建一個WrapLabelAttachment,繼承自LabelAttachment,然后通過在一個JTextArea,設置文字,setLineWrap(true),指定JTextArea的寬度,然后把JTextArea 的 內容繪制這個Attachment;在實現的過程中,發現JTextArea 有一個bug,就是折行的計算不準確,總是在右邊留下很大的空白; 如下圖:

          測試代碼:
            1 package demo.text;
            2 
            3 import java.awt.*;
            4 import java.awt.font.*;
            5 import java.text.*;
            6 import javax.swing.*;
            7 import twaver.network.ui.*;
            8 
            9 public class WrapLabelAttachment extends LabelAttachment {
           10 
           11 //    private final MyTextArea label = new MyTextArea();
           12     private final JTextArea  label = new JTextArea();
           13     protected int maxLength;
           14     private LabelBorder lbBorder = null;
           15     public WrapLabelAttachment(ElementUI ui) {
           16         super(ui);
           17         this.updateLabel();
           18     }
           19 
           20     private void updateLabel() {
           21         label.setOpaque(false);
           22         label.setAutoscrolls(false);
           23         label.setText(this.getLabelContent());
           24         label.setFont(font);
           25         label.setBorder(null);
           26         label.setLineWrap(true);
           27         if(this.border){
           28             if(lbBorder == null){
           29                 lbBorder = new LabelBorder(1);
           30             }
           31             label.setBorder(lbBorder);
           32         }
           33     }
           34 
           35     protected String getLabelContent() {
           36         Object content = element.getName();
           37         if (content == null) {
           38             return null;
           39         } else {
           40             return content.toString();
           41         }
           42     }
           43 
           44     protected void update() {
           45         this.updateLabel();
           46     }
           47 
           48     public void paintName(Graphics2D g2d, String elementLabel) {
           49         Rectangle bounds = getBounds();
           50 //        MyTextArea renderer = label;
           51         JTextArea renderer = label;
           52         String text = getLabelContent();
           53         if (highlightable && element.isSelected() && network.isSelectedStatePaintable(element)) {
           54             renderer.setOpaque(true);
           55             renderer.setBackground(this.highlightBackground);
           56             renderer.setForeground(this.highlightForeground);
           57         } else {
           58             if (this.background == null) {
           59                 renderer.setOpaque(false);
           60             } else {
           61                 renderer.setOpaque(true);
           62                 renderer.setBackground(this.background);
           63             }
           64             renderer.setForeground(this.color);
           65         }
           66         if(this.border){
           67             // draw border
           68             lbBorder.setBorderVisible(this.border);
           69             lbBorder.setBorderStroke(this.borderStroke);
           70             lbBorder.setLineColor(this.borderColor);
           71 
           72             // draw outline
           73             lbBorder.setUnderlineVisible(this.underline);
           74             lbBorder.setUnderlineStroke(this.underlineStroke);
           75             lbBorder.setUnderlineColor(this.underlineColor);    
           76         }
           77         
           78         if (text != null) {
           79             renderer.setBounds(0, 0, bounds.width, bounds.height);
           80             g2d.translate(bounds.x, bounds.y);
           81             renderer.paint(g2d);
           82             g2d.translate(-bounds.x, -bounds.y);
           83         }
           84     }
           85     
           86     public class MyTextArea extends JComponent {
           87         private String t = "";
           88         public void setText(String t){
           89             this.t = t;
           90         }
           91         
           92         public String getText(){
           93             return t;
           94         }
           95         
           96         public void paint(Graphics g) {
           97             super.paint(g);
           98             if(this.isOpaque()){
           99                 g.setColor(this.getBackground());
          100                 g.fillRect(0, 0, this.getWidth(), this.getHeight());
          101                 g.setColor(highlightForeground);
          102             }
          103             Graphics2D g2d = (Graphics2D) g;
          104             g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
          105             g2d.setFont(font);
          106             AttributedString messageAS = new AttributedString(getText());
          107             messageAS.addAttribute(TextAttribute.FONT,WrapLabelAttachment.this.getFont());
          108             AttributedCharacterIterator messageIterator = messageAS.getIterator();
          109             FontRenderContext messageFRC = g2d.getFontRenderContext();
          110             LineBreakMeasurer messageLBM = new LineBreakMeasurer(messageIterator,
          111                 messageFRC);
          112 
          113             Insets insets = getInsets();
          114             float wrappingWidth = getSize().width - insets.left - insets.right;
          115             float x = insets.left;
          116             float y = insets.top;
          117 
          118             while (messageLBM.getPosition() < messageIterator.getEndIndex()) {
          119               TextLayout textLayout = messageLBM.nextLayout(wrappingWidth);
          120               y += textLayout.getAscent();
          121               textLayout.draw(g2d, x, y);
          122               y += textLayout.getDescent() + textLayout.getLeading();
          123               x = insets.left;
          124             }
          125           }
          126     }
          127 
          128     public Rectangle getBounds() {
          129         updateLabel();
          130         Rectangle rect = super.getBounds();
          131         if (element.getClientProperty("Label_Max_Width") != null) {
          132             this.maxLength = Integer.valueOf(element.getClientProperty("Label_Max_Width").toString());
          133             if (this.maxLength > 0 && this.maxLength < rect.width) {
          134                 rect.x += (rect.width - this.maxLength) / 2;
          135                 rect.height = rect.height * rect.width / this.maxLength + 1;
          136                 rect.width = this.maxLength;
          137             }
          138         }
          139         return rect;
          140     }
          141 }

          最后通過自己定制一個MyTextArea來實現,在MyTextArea中,用LineBreakMeasurer來計算動態折行:
          代碼:
           1 public class MyTextArea extends JComponent {
           2         private String t = "";
           3         public void setText(String t){
           4             this.t = t;
           5         }
           6         
           7         public String getText(){
           8             return t;
           9         }
          10         
          11         public void paint(Graphics g) {
          12             super.paint(g);
          13             if(this.isOpaque()){
          14                 g.setColor(this.getBackground());
          15                 g.fillRect(0, 0, this.getWidth(), this.getHeight());
          16                 g.setColor(highlightForeground);
          17             }
          18             Graphics2D g2d = (Graphics2D) g;
          19             g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
          20             g2d.setFont(font);
          21             AttributedString messageAS = new AttributedString(getText());
          22             messageAS.addAttribute(TextAttribute.FONT,WrapLabelAttachment.this.getFont());
          23             AttributedCharacterIterator messageIterator = messageAS.getIterator();
          24             FontRenderContext messageFRC = g2d.getFontRenderContext();
          25             LineBreakMeasurer messageLBM = new LineBreakMeasurer(messageIterator,
          26                 messageFRC);
          27 
          28             Insets insets = getInsets();
          29             float wrappingWidth = getSize().width - insets.left - insets.right;
          30             float x = insets.left;
          31             float y = insets.top;
          32 
          33             while (messageLBM.getPosition() < messageIterator.getEndIndex()) {
          34               TextLayout textLayout = messageLBM.nextLayout(wrappingWidth);
          35               y += textLayout.getAscent();
          36               textLayout.draw(g2d, x, y);
          37               y += textLayout.getDescent() + textLayout.getLeading();
          38               x = insets.left;
          39             }
          40           }
          41     }

           然后重寫WrapLabelAttachment的 paintName 方法 和getBounds 方法:
          代碼:
           1 public void paintName(Graphics2D g2d, String elementLabel) {
           2         Rectangle bounds = getBounds();
           3         MyTextArea renderer = label;
           4 //        JTextArea renderer = label;
           5         String text = getLabelContent();
           6         if (highlightable && element.isSelected() && network.isSelectedStatePaintable(element)) {
           7             renderer.setOpaque(true);
           8             renderer.setBackground(this.highlightBackground);
           9             renderer.setForeground(this.highlightForeground);
          10         } else {
          11             if (this.background == null) {
          12                 renderer.setOpaque(false);
          13             } else {
          14                 renderer.setOpaque(true);
          15                 renderer.setBackground(this.background);
          16             }
          17             renderer.setForeground(this.color);
          18         }
          19         if(this.border){
          20             // draw border
          21             lbBorder.setBorderVisible(this.border);
          22             lbBorder.setBorderStroke(this.borderStroke);
          23             lbBorder.setLineColor(this.borderColor);
          24 
          25             // draw outline
          26             lbBorder.setUnderlineVisible(this.underline);
          27             lbBorder.setUnderlineStroke(this.underlineStroke);
          28             lbBorder.setUnderlineColor(this.underlineColor);    
          29         }
          30         
          31         if (text != null) {
          32             renderer.setBounds(0, 0, bounds.width, bounds.height);
          33             g2d.translate(bounds.x, bounds.y);
          34             renderer.paint(g2d);
          35             g2d.translate(-bounds.x, -bounds.y);
          36         }
          37     }
          38 

          代碼:
           1 public Rectangle getBounds() {
           2         updateLabel();
           3         Rectangle rect = super.getBounds();
           4         if (element.getClientProperty("Label_Max_Width") != null) {
           5             this.maxLength = Integer.valueOf(element.getClientProperty("Label_Max_Width").toString());
           6             if (this.maxLength > 0 && this.maxLength < rect.width) {
           7                 rect.x += (rect.width - this.maxLength) / 2;
           8                 rect.height = rect.height * rect.width / this.maxLength + 1;
           9                 rect.width = this.maxLength;
          10             }
          11         }
          12         return rect;
          13     }
          14 

          getBounds方法需要動態計算rect 的寬高。 最終效果圖:

          全部代碼見附件: WrapLabelDemo

          評論

          # re: 如何指定Node的Label的最大寬度  回復  更多評論   

          2013-10-23 15:44 by 渣漿泵
          這段代碼剛好能用上,謝了

          # re: 如何指定Node的Label的最大寬度  回復  更多評論   

          2014-08-09 20:18 by 司馬青衫
          不錯不錯。。謝謝分享







          文學論壇www.simaqingshan.com

          只有注冊用戶登錄后才能發表評論。


          網站導航:
          博客園   IT新聞   Chat2DB   C++博客   博問  
           
          主站蜘蛛池模板: 桑植县| 巴南区| 德化县| 西藏| 中西区| 泽普县| 喀什市| 英德市| 山丹县| 正镶白旗| 田林县| 柳江县| 施甸县| 泌阳县| 鱼台县| 乐至县| 广安市| 始兴县| 莱州市| 靖宇县| 彩票| 永顺县| 从化市| 宁安市| 基隆市| 左贡县| 慈溪市| 旬阳县| 调兵山市| 晋州市| 廉江市| 寻甸| 民县| 迁安市| 垦利县| 广安市| 马尔康县| 博客| 玉屏| 四平市| 海兴县|