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
继续正常工作,但不会意识到文字的更改。)然而,如果文字更改是插入或删除单个字符,现有的LineBreakMeasurer
可以通过调用insertChar
或更新deleteChar
。 更新现有的LineBreakMeasurer
比创建新的更快。 基于用户输入修改文本的客户端应该利用这些方法。
示例 :
在组件中渲染段落
public void paint(Graphics graphics) { Point2D pen = new Point2D(10, 20); Graphics2D g2d = (Graphics2D)graphics; FontRenderContext frc = g2d.getFontRenderContext(); // let styledText be an AttributedCharacterIterator containing at least // one character LineBreakMeasurer measurer = new LineBreakMeasurer(styledText, frc); float wrappingWidth = getSize().width - 15; while (measurer.getPosition() < fStyledText.length()) { TextLayout layout = measurer.nextLayout(wrappingWidth); pen.y += (layout.getAscent()); float dx = layout.isLeftToRight() ? 0 : (wrappingWidth - layout.getAdvance()); layout.draw(graphics, pen.x + dx, pen.y); pen.y += 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
Constructor and Description |
---|
LineBreakMeasurer(AttributedCharacterIterator text, BreakIterator breakIter, FontRenderContext frc)
为指定的文本构造一个
LineBreakMeasurer 。
|
LineBreakMeasurer(AttributedCharacterIterator text, FontRenderContext frc)
为指定的文本构造一个
LineBreakMeasurer 。
|
Modifier and Type | Method and Description |
---|---|
void |
deleteChar(AttributedCharacterIterator newParagraph, int deletePos)
从文本中删除单个
LineBreakMeasurer 后更新此
LineBreakMeasurer ,并将当前位置设置为段落的开头。
|
int |
getPosition()
返回此
LineBreakMeasurer 的当前位置。
|
void |
insertChar(AttributedCharacterIterator newParagraph, int insertPos)
将单个字符插入文本后,更新此
LineBreakMeasurer ,并将当前位置设置为段落的开头。
|
TextLayout |
nextLayout(float wrappingWidth)
返回下一个布局,并更新当前位置。
|
TextLayout |
nextLayout(float wrappingWidth, int offsetLimit, boolean requireNextWord)
返回下一个布局,并更新当前位置。
|
int |
nextOffset(float wrappingWidth)
返回下一个布局末尾的位置。
|
int |
nextOffset(float wrappingWidth, int offsetLimit, boolean requireNextWord)
返回下一个布局末尾的位置。
|
void |
setPosition(int newPosition)
设置此
LineBreakMeasurer 的当前位置。
|
public LineBreakMeasurer(AttributedCharacterIterator text, FontRenderContext frc)
LineBreakMeasurer
。
text
-应用此文本LineBreakMeasurer
产生TextLayout
对象;
该文本必须至少包含一个字符;
如果通过iter
的文本发生变化,则对此LineBreakMeasurer
实例的进一步调用未定义(除了在某些情况下,当insertChar
调用insertChar或deleteChar
时,请参见下文)
frc
- 包含有关正确测量文本所需的图形设备信息;
文本测量可能会因设备分辨率和抗锯齿等属性而略有不同。
此参数不指定LineBreakMeasurer
与用户空间之间的LineBreakMeasurer
insertChar(java.text.AttributedCharacterIterator, int)
,
deleteChar(java.text.AttributedCharacterIterator, int)
public LineBreakMeasurer(AttributedCharacterIterator text, BreakIterator breakIter, FontRenderContext frc)
LineBreakMeasurer
。
text
- 这个LineBreakMeasurer
生成TextLayout
对象的文本;
该文本必须至少包含一个字符;
如果通过iter
的文本发生变化,则对此LineBreakMeasurer
实例的进一步调用未定义(除了在某些情况下,当insertChar
调用insertChar或deleteChar
时,请参见下文)
breakIter
- 定义换行符的BreakIterator
frc
- 包含有关正确测量文本所需的图形设备信息;
文本测量可能会因设备分辨率和抗锯齿等属性而略有不同。
该参数不指定LineBreakMeasurer
与用户空间之间的LineBreakMeasurer
IllegalArgumentException
- 文本是否少于一个字符
insertChar(java.text.AttributedCharacterIterator, int)
,
deleteChar(java.text.AttributedCharacterIterator, int)
public int nextOffset(float wrappingWidth)
LineBreakMeasurer
的当前位置。
wrappingWidth
- 下一个布局文本允许的最大可见行进
TextLayout
的限制。
public int nextOffset(float wrappingWidth, int offsetLimit, boolean requireNextWord)
LineBreakMeasurer
的当前位置。
wrappingWidth
- 下一个布局文本允许的最大可见提前
offsetLimit
- 下一个布局中不能包含的第一个字符,即使限制后的文本也适合包装宽度;
offsetLimit
必须大于当前位置
requireNextWord
- 如果true
,如果整个下一个字不符合wrappingWidth
,则返回的当前位置;
如果false
,返回的偏移量至少比当前位置大一个
TextLayout
的限制
public TextLayout nextLayout(float wrappingWidth)
wrappingWidth
- 下一个布局文本允许的最大可见提前
TextLayout
,从当前位置开始,代表下一行拟合
wrappingWidth
public TextLayout nextLayout(float wrappingWidth, int offsetLimit, boolean requireNextWord)
wrappingWidth
- 下一个布局文本允许的最大可见提前
offsetLimit
- 下一个布局中无法包含的第一个字符,即使限制后的文本也适合包装宽度;
offsetLimit
必须大于当前位置
requireNextWord
- 如果是true
,如果当前位置的整个字不适合包装宽度,则返回null
。
如果false
,返回一个有效的布局,至少包含当前位置的字符
TextLayout
,从当前位置开始,表示下一行拟合在wrappingWidth
内。
如果当前位置在此LineBreakMeasurer
使用的文本的LineBreakMeasurer
,则返回null
public int getPosition()
LineBreakMeasurer
的当前位置。
LineBreakMeasurer
的当前位置
setPosition(int)
public void setPosition(int newPosition)
LineBreakMeasurer
的当前位置。
newPosition
- 这个LineBreakMeasurer
的当前位置;
该位置应在用于构建此LineBreakMeasurer
的文本内(或最近传递给insertChar
或deleteChar
getPosition()
public void insertChar(AttributedCharacterIterator newParagraph, int insertPos)
LineBreakMeasurer
,并将当前位置设置为段落的开头。
newParagraph
- 插入后的文字
insertPos
- 插入字符的文本中的位置
IndexOutOfBoundsException
-如果
insertPos
小于开始
newParagraph
,或者大于或等于的端
newParagraph
NullPointerException
- 如果
newParagraph
是
null
deleteChar(java.text.AttributedCharacterIterator, int)
public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos)
LineBreakMeasurer
后,更新此
LineBreakMeasurer
,并将当前位置设置为段落的开头。
newParagraph
- 删除后的文字
deletePos
- 字符被删除的文本中的位置
IndexOutOfBoundsException
-如果
deletePos
小于开始
newParagraph
或大于的端
newParagraph
NullPointerException
- 如果
newParagraph
是
null
insertChar(java.text.AttributedCharacterIterator, int)