Module  java.desktop
软件包  java.awt.font

Class LineBreakMeasurer



  • public final class LineBreakMeasurer
    extends Object
    LineBreakMeasurer类允许将样式文本分解成符合特定视觉进步的线(或段)。 这对于希望显示适合特定宽度的文本段(称为包装宽度)的客户端是有用的。

    LineBreakMeasurer用样式文本的迭代器构造。 迭代器的范围应该是文本中的一个段落。 LineBreakMeasurer在文本中保留开始下一个文本段的位置。 最初,这个位置是文本的开始。 根据双向格式规则,段落被分配一个整体方向(从左到右或从右到左)。 从段落获得的所有分段具有与段落相同的方向。

    通过调用方法nextLayout获得文本段,该方法返回表示适合包装宽度的文本的TextLayout nextLayout方法将当前位置移动到从nextLayout返回的布局的nextLayout

    LineBreakMeasurer实现了最常用的划线策略:适合包装宽度的每个单词都放在行上。 如果第一个字不适合,那么适合包装宽度的所有字符都放在行上。 每条线上至少放置一个字符。

    TextLayout返回的TextLayout实例LineBreakMeasurer标签视为0宽度的空格。 希望获取制表符分隔段以进行定位的客户端应使用nextLayout的超负荷,该超负荷在nextLayout中进行了限制。 限制偏移应该是标签后的第一个字符。 从此方法返回的TextLayout对象以提供的限制结束(或之前,如果当前位置和限制之间的文本将完全不适合包装宽度)。

    布局制表符分隔文本的客户在第一个细分受众群放在一行之后,需要略有不同的破产政策。 不要在剩余空间中拟合部分单词,而应将下一行中不完整的单词放在剩余空间中。 可以在nextLayout的过载中请求此策略的更改,该参数需要boolean参数。 如果此参数为true ,如果第一个字不适合给定的空间,则nextLayout返回null 请参阅下面的选项卡示例。

    一般来说,如果用于构建LineBreakMeasurer的文本发生更改, LineBreakMeasurer必须构建新的LineBreakMeasurer以反映更改。 (旧的LineBreakMeasurer继续正常工作,但不会意识到文本的更改。)然而,如果文本更改是插入或删除单个字符,现有的LineBreakMeasurer可以通过调用insertChar或更新deleteChar 更新现有的LineBreakMeasurer比创建新的更快。 基于用户输入修改文本的客户端应该利用这些方法。

    示例

    在组件中渲染段落

    
     public void paint(Graphics graphics) {
    
         float dx = 0f, dy = 5f;
         Graphics2D g2d = (Graphics2D)graphics;
         FontRenderContext frc = g2d.getFontRenderContext();
    
         AttributedString text = new AttributedString(".....");
         AttributedCharacterIterator paragraph = text.getIterator();
    
         LineBreakMeasurer measurer = new LineBreakMeasurer(paragraph, frc);
         measurer.setPosition(paragraph.getBeginIndex());
         float wrappingWidth = (float)getSize().width;
    
         while (measurer.getPosition() < paragraph.getEndIndex()) {
    
             TextLayout layout = measurer.nextLayout(wrappingWidth);
    
             dy += (layout.getAscent());
             float dx = layout.isLeftToRight() ?
                 0 : (wrappingWidth - layout.getAdvance());
    
             layout.draw(graphics, dx, dy);
             dy += layout.getDescent() + layout.getLeading();
         }
     }
     

    用标签渲染文本。 为简单起见,假定整个文本方向是从左到右

    
     public void paint(Graphics graphics) {
    
         float leftMargin = 10, rightMargin = 310;
         float[] tabStops = { 100, 250 };
    
         // assume styledText is an AttributedCharacterIterator, and the number
         // of tabs in styledText is tabCount
    
         int[] tabLocations = new int[tabCount+1];
    
         int i = 0;
         for (char c = styledText.first(); c != styledText.DONE; c = styledText.next()) {
             if (c == '\t') {
                 tabLocations[i++] = styledText.getIndex();
             }
         }
         tabLocations[tabCount] = styledText.getEndIndex() - 1;
    
         // Now tabLocations has an entry for every tab's offset in
         // the text.  For convenience, the last entry is tabLocations
         // is the offset of the last character in the text.
    
         LineBreakMeasurer measurer = new LineBreakMeasurer(styledText);
         int currentTab = 0;
         float verticalPos = 20;
    
         while (measurer.getPosition() < styledText.getEndIndex()) {
    
             // Lay out and draw each line.  All segments on a line
             // must be computed before any drawing can occur, since
             // we must know the largest ascent on the line.
             // TextLayouts are computed and stored in a Vector;
             // their horizontal positions are stored in a parallel
             // Vector.
    
             // lineContainsText is true after first segment is drawn
             boolean lineContainsText = false;
             boolean lineComplete = false;
             float maxAscent = 0, maxDescent = 0;
             float horizontalPos = leftMargin;
             Vector layouts = new Vector(1);
             Vector penPositions = new Vector(1);
    
             while (!lineComplete) {
                 float wrappingWidth = rightMargin - horizontalPos;
                 TextLayout layout =
                         measurer.nextLayout(wrappingWidth,
                                             tabLocations[currentTab]+1,
                                             lineContainsText);
    
                 // layout can be null if lineContainsText is true
                 if (layout != null) {
                     layouts.addElement(layout);
                     penPositions.addElement(new Float(horizontalPos));
                     horizontalPos += layout.getAdvance();
                     maxAscent = Math.max(maxAscent, layout.getAscent());
                     maxDescent = Math.max(maxDescent,
                         layout.getDescent() + layout.getLeading());
                 } else {
                     lineComplete = true;
                 }
    
                 lineContainsText = true;
    
                 if (measurer.getPosition() == tabLocations[currentTab]+1) {
                     currentTab++;
                 }
    
                 if (measurer.getPosition() == styledText.getEndIndex())
                     lineComplete = true;
                 else if (horizontalPos >= tabStops[tabStops.length-1])
                     lineComplete = true;
    
                 if (!lineComplete) {
                     // move to next tab stop
                     int j;
                     for (j=0; horizontalPos >= tabStops[j]; j++) {}
                     horizontalPos = tabStops[j];
                 }
             }
    
             verticalPos += maxAscent;
    
             Enumeration layoutEnum = layouts.elements();
             Enumeration positionEnum = penPositions.elements();
    
             // now iterate through layouts and draw them
             while (layoutEnum.hasMoreElements()) {
                 TextLayout nextLayout = (TextLayout) layoutEnum.nextElement();
                 Float nextPosition = (Float) positionEnum.nextElement();
                 nextLayout.draw(graphics, nextPosition.floatValue(), verticalPos);
             }
    
             verticalPos += maxDescent;
         }
     }
     
    另请参见:
    TextLayout
    • 方法详细信息

      • nextOffset

        public int nextOffset​(float wrappingWidth)
        返回下一个布局末尾的位置。 不更新此LineBreakMeasurer的当前位置。
        参数
        wrappingWidth - 下一个布局文本允许的最大可见提前
        结果
        文字中的偏移量代表下一个 TextLayout的限制。
      • nextOffset

        public int nextOffset​(float wrappingWidth,
                              int offsetLimit,
                              boolean requireNextWord)
        返回下一个布局末尾的位置。 不更新此LineBreakMeasurer的当前位置。
        参数
        wrappingWidth - 下一个布局文本允许的最大可见提前
        offsetLimit - 下一个布局中无法包含的第一个字符,即使限制后的文本也适合包装宽度; offsetLimit必须大于当前位置
        requireNextWord - 如果是true ,如果整个下一个字不符合wrappingWidth ,返回的当前位置; 如果为false ,返回的偏移量至少比当前位置大一个
        结果
        文字中的偏移量代表下一个 TextLayout的限制
      • nextLayout

        public TextLayout nextLayout​(float wrappingWidth)
        返回下一个布局,并更新当前位置。
        参数
        wrappingWidth - 下一个布局文本允许的最大可见提前
        结果
        一个 TextLayout ,从当前位置开始,代表下一行拟合 wrappingWidth
      • nextLayout

        public TextLayout nextLayout​(float wrappingWidth,
                                     int offsetLimit,
                                     boolean requireNextWord)
        返回下一个布局,并更新当前位置。
        参数
        wrappingWidth - 下一个布局文本允许的最大可见提前
        offsetLimit - 下一个布局中不能包含的第一个字符,即使限制后的文本也适合包装宽度; offsetLimit必须大于当前位置
        requireNextWord - 如果是true ,如果当前位置的整个字不适合包装宽度,则返回null 如果是false ,则返回一个至少包含当前位置字符的有效布局
        结果
        一个TextLayout ,从当前位置开始,代表wrappingWidth的下一行。 如果当前位置在该LineBreakMeasurer使用的文本的LineBreakMeasurer ,则返回null
      • getPosition

        public int getPosition​()
        返回此 LineBreakMeasurer的当前位置。
        结果
        这个 LineBreakMeasurer的当前位置
        另请参见:
        setPosition(int)
      • setPosition

        public void setPosition​(int newPosition)
        设置此 LineBreakMeasurer的当前位置。
        参数
        newPosition -此的当前位置LineBreakMeasurer ; 该位置应在用于构建此文本的文本内LineBreakMeasurer (或在最近传递给insertChardeleteChar
        另请参见:
        getPosition()