public final class LineBreakMeasurer extends Object
LineBreakMeasurer
クラスを使用すれば、書式付きテキストを、特定の可視有効幅に収まる行 (またはセグメント) に分けることができます。これは、固有の幅 (ラッピング幅と呼ばれる) に収まるテキストの段落をクライアントに表示する場合に便利です。
LineBreakMeasurer
は、書式付きテキストに対するイテレータを使って構築されます。イテレータの範囲はテキスト内の 1 つの段落です。LineBreakMeasurer
は、次のテキストセグメントを開始するための、テキスト内の位置を保持します。最初は、この位置がテキストの始点です。段落の方向は、双方向フォーマット規則に従って、全方向 (左から右または右から左) に及びます。段落から取得されたすべてのセグメントは、その段落と同じ方向になります。
テキストのセグメントは、nextLayout
メソッドを呼び出すことで取得されます。このメソッドは、ラッピング幅に収まるテキストを表すTextLayout
を返します。nextLayout
メソッドは、nextLayout
が返したレイアウトの終端に現在の位置を移動します。
LineBreakMeasurer
は、もっとも一般的に使用される次のような改行ポリシーを実装します。ラッピング幅に収まるすべての単語は、同じ行に配置されます。最初の単語が収まらなければ、ラッピング幅に収まるだけの文字がその行に配置されます。各行には少なくとも 1 文字が配置されます。
LineBreakMeasurer
によって返される TextLayout
のインスタンスは、タブを幅 0 のスペースと同様に扱います。位置決めのためにタブ区切りのセグメントを取得するクライアントは、テキストに対するリミットオフセットをとる nextLayout
のオーバーロードを使うようにしてください。リミットオフセットは、タブ以降の最初の文字です。このメソッドが返す TextLayout
オブジェクトは、指定されたリミット (現在の位置とリミットとの間のテキスト全体がラッピング幅に収まらない場合には、リミットの前) で終わります。
タブ区切りのテキストをレイアウトするクライアントには、最初のセグメントを行に配置したあと、やや異なる改行ポリシーが必要です。残りの領域に一部の単語を収めるのではなく、全体を次の行に配置します。ポリシーのこの変更は、boolean
パラメータをとる nextLayout
のオーバーロードで要求できます。このパラメータが true
の場合、nextLayout
は、最初の単語が指定された領域に収まらないときに null
を返します。下記のタブサンプルを参照してください。
通常、LineBreakMeasurer
の作成に使用されたテキストが変更された場合は、変更を反映するために新しい LineBreakMeasurer
を作成する必要があります。(これまでの LineBreakMeasurer
はそのまま正常に動作するが、テキストの変更には対応しない。)ただし、テキストの変更が 1 文字の挿入または削除の場合には、insertChar
または deleteChar
を呼び出して、既存の LineBreakMeasurer
を「更新」してもかまいません。既存の 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
コンストラクタと説明 |
---|
LineBreakMeasurer(AttributedCharacterIterator text, BreakIterator breakIter, FontRenderContext frc)
指定されたテキストに対する
LineBreakMeasurer を構築します。 |
LineBreakMeasurer(AttributedCharacterIterator text, FontRenderContext frc)
指定されたテキストに対する
LineBreakMeasurer を構築します。 |
修飾子と型 | メソッドと説明 |
---|---|
void |
deleteChar(AttributedCharacterIterator newParagraph, int deletePos)
テキストから文字が 1 つ削除されたあとに
LineBreakMeasurer を更新して、現在の位置をその段落の先頭に設定します。 |
int |
getPosition()
この
LineBreakMeasurer の現在の位置を返します。 |
void |
insertChar(AttributedCharacterIterator newParagraph, int insertPos)
テキストに文字が 1 つ挿入されたあとに
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
オブジェクトの生成対象とするテキスト。このテキストには、1 つ以上の文字が含まれていなければならない。iter
で得られるテキストが変更された場合、その後のこの LineBreakMeasurer
のインスタンスへの呼び出しの結果は保証されない (ただし、あとで insertChar
または deleteChar
を呼び出す場合を除く。関連項目を参照)frc
- テキストを正確に測定するために必要なグラフィックスデバイスに関する情報を格納する。テキスト測定は、デバイスの解像度によりわずかに異なり、アンチエイリアスなどの属性によっても異なる。このパラメータは、LineBreakMeasurer
とユーザー空間の間の変換は指定しない。insertChar(java.text.AttributedCharacterIterator, int)
, deleteChar(java.text.AttributedCharacterIterator, int)
public LineBreakMeasurer(AttributedCharacterIterator text, BreakIterator breakIter, FontRenderContext frc)
LineBreakMeasurer
を構築します。text
- この LineBreakMeasurer
が TextLayout
オブジェクトの生成対象とするテキスト。このテキストには、1 つ以上の文字が含まれていなければならない。iter
で得られるテキストが変更された場合、その後のこの LineBreakMeasurer
のインスタンスへの呼び出しの結果は保証されない (ただし、あとで insertChar
または deleteChar
を呼び出す場合を除く。関連項目を参照)breakIter
- 改行を定義する BreakIterator
frc
- テキストを正確に測定するために必要なグラフィックスデバイスに関する情報を格納する。テキスト測定は、デバイスの解像度によりわずかに異なり、アンチエイリアスなどの属性によっても異なる。このパラメータは、LineBreakMeasurer
とユーザー空間の間の変換は指定しない。IllegalArgumentException
- テキストが 1 文字に満たない場合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
の場合、返されるオフセットは現在の位置よりも少なくとも 1 大きいTextLayout
のリミットを表す、テキスト内のオフセットpublic TextLayout nextLayout(float wrappingWidth)
wrappingWidth
- 次のレイアウト内のテキストに許容される最大の可視有効幅wrappingWidth
に収まる次の行を表し、現在の位置から始まる TextLayout
public TextLayout nextLayout(float wrappingWidth, int offsetLimit, boolean requireNextWord)
wrappingWidth
- 次のレイアウト内のテキストに許容される最大の可視有効幅offsetLimit
- リミット以降のテキストがラッピング幅に収まる場合でも、次のレイアウトに含まれない最初の文字。offsetLimit
は、現在の位置よりも大きくなければならない。requireNextWord
- true
の場合、現在の位置にある単語全体がラッピング幅に収まらないときは null
が返される。false
の場合、少なくとも現在の位置にある文字を含む、有効なレイアウトが返されるwrappingWidth
に収まる次の行を表し、現在の位置から始まる TextLayout
。現在の位置が、この 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
を更新して、現在の位置をその段落の先頭に設定します。newParagraph
- 削除後のテキストdeletePos
- テキスト内の、文字が削除された位置IndexOutOfBoundsException
- deletePos
が newParagraph
の開始位置より前、または newParagraph
の終了位置より後ろである場合NullPointerException
- newParagraph
が null
である場合insertChar(java.text.AttributedCharacterIterator, int)
バグまたは機能を送信
詳細な API リファレンスおよび開発者ドキュメントについては、Java SE のドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright © 1993, 2013, Oracle and/or its affiliates. All rights reserved.