模块  java.desktop
软件包  java.awt.font

Class LineBreakMeasurer


  • public final class LineBreakMeasurer
    extends Object
    LineBreakMeasurer类允许将样式化文本分解为适合特定视觉前进的行(或段)。 这对于希望显示适合特定宽度的文本段落(称为包装宽度)的客户非常有用。

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

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

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

    TextLayout情况下,通过返回LineBreakMeasurer对待标签如0角空格。 希望获得制表符分隔的定位段的客户端应使用nextLayout的重载,该过载在nextLayout中采用限制偏移量。 限制偏移量应该是选项卡后面的第一个字符。 从此方法返回的TextLayout对象以提供的限制结束(或者之前,如果当前位置和限制之间的文本不完全适合包装宽度)。

    在将第一个段放置在一条线上之后,正在布置制表符分隔文本的客户端需要稍微不同的换行策略。 它们不应该在剩余空间中拟合部分单词,而应将完全不适合剩余空间的单词放在下一行。 可以在nextLayout的超载中请求此策略更改,该参数采用boolean参数。 如果此参数为true ,则如果第一个单词不适合给定空间,则nextLayout将返回null 请参阅下面的选项卡示例。

    通常,如果用于构造LineBreakMeasurer的文本发生更改, LineBreakMeasurer必须构造新的LineBreakMeasurer以反映更改。 (旧的LineBreakMeasurer继续正常运行,但它不会知道文本更改。)尽管如此,如果文本更改是插入或删除单个字符, LineBreakMeasurer可以通过调用insertChar或更新现有的insertChardeleteChar 更新现有的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
    • 构造方法详细信息

      • LineBreakMeasurer

        public LineBreakMeasurer​(AttributedCharacterIterator text,
                                 FontRenderContext frc)
        为指定的文本构造一个 LineBreakMeasurer
        参数
        text - 此LineBreakMeasurer生成TextLayout对象的文本; 文本必须至少包含一个字符; 如果通过iter提供的文本发生更改,则对此LineBreakMeasurer实例的进一步调用未定义(在某些情况下,以后调用insertChardeleteChar时 - 请参见下文)
        frc - 包含有关正确测量文本所需的图形设备的信息; 文本测量值可能会略有不同,具体取决于设备分辨率和抗锯齿等属性; 此参数未指定LineBreakMeasurer与用户空间之间的LineBreakMeasurer
        另请参见:
        insertChar(java.text.AttributedCharacterIterator, int)deleteChar(java.text.AttributedCharacterIterator, int)
    • 方法详细信息

      • 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 ,则返回的偏移量至少比当前位置大1
        结果
        表示下一个 TextLayout限制的文本中的偏移量
      • nextLayout

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

        public TextLayout nextLayout​(float wrappingWidth,
                                     int offsetLimit,
                                     boolean requireNextWord)
        返回下一个布局,并更新当前位置。
        参数
        wrappingWidth - 下一个布局中文本允许的最大可见提前量
        offsetLimit - 第一个不能包含在下一个布局中的字符,即使限制后的文本适合包装宽度; offsetLimit必须大于当前位置
        requireNextWord - 如果是true ,并且如果当前位置的整个单词不适合包装宽度,则返回null 如果是false ,则返回有效布局,该布局至少包括当前位置的字符
        结果
        a 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()