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

Class LineBreakMeasurer


  • public final class LineBreakMeasurerextends 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()