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 阅读(1897) 评论(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

只有注册用户登录后才能发表评论。


网站导航: