モジュール java.desktop
パッケージ java.awt.font

クラスLineBreakMeasurer

java.lang.Object
java.awt.font.LineBreakMeasurer

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) {

     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(Float.valueOf(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;
     }
 }
 

関連項目: