SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Swing再入門

Swing再入門 マウスで選択可能なマルチフォントテキストの描画

第5回 マルチフォントの描画と応用例

テキストを折り返し表示する

 続いて、「長いテキストを折り返し表示する」ことについて考えてみましょう。テキストをAttributedStringとして用意し、描画の際にAttributedCharacterIteratorインスタンスを取り出すという点は同じです。

 折り返し表示には、取り出されたAttributedCharacterIteratorから、一定幅分のテキストのレイアウトに関するオブジェクトを取り出し、描画する、といった作業を行っていきます。では、これも例を挙げて説明しましょう。

頭の方にimport文を追加し、G2Panelを書き換える
// import文を追加
import java.awt.font.*;
import java.awt.geom.Rectangle2D;

/* Sample クラス部分は省略 */

class G2Panel extends JPanel {
    private static final long serialVersionUID = 1L;

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;
        Font f1 = new Font("Dialog",Font.PLAIN,24);
        String str1 = "これは、折り返し表示をするサンプルです。";
        AttributedString as1 = new AttributedString(str1);
        as1.addAttribute(TextAttribute.FONT,f1);
        AttributedCharacterIterator ac1 = as1.getIterator();
        FontRenderContext fc1 = g2.getFontRenderContext();
        LineBreakMeasurer m1 = new LineBreakMeasurer(ac1,fc1);
        float y = 50; // 最初の描画位置
        while (m1.getPosition() < str1.length()) {
            TextLayout tl1 = m1.nextLayout(150); // 折り返し幅
            tl1.draw(g2, 20, y); // 取得行の描画
            y += tl1.getBounds().getHeight() + 10; // 次行との間隔
        }
        // 以下はテキストの描画領域の枠線の表示
        g2.setPaint(Color.red);
        m1.setPosition(0);
        Rectangle2D r1 = new Rectangle2D.Float(
            20,50 - m1.nextLayout(150).getAscent(),150,y - 50);
        g2.draw(r1);
    }
}

 ここでは、修正したG2Panelクラスのみ掲載しておきました。str1に指定したテキストを、150ドット幅で折り返し表示しています。この幅は、自由に調整することができます。

LineBreakMeasurerとTextLayout

 折り返し表示では、全部で3つのクラスが重要な働きをします。

  • FontRenderContext
  • テキストの各種寸法の測定に関する情報を管理するクラスです。描画の際には、Graphics2Dからこのインスタンスを取り出し、利用します。
  • LineBreakMeasurer
  • テキストを、一定間隔で切り分けるためのメジャー(物差し)としての働きをするクラスです。この物差しを使ってテキストを一定間隔で切り分けていく、と考えてください。
  • TextLayout
  • LineBreakMeasurerから取り出される、テキストのレイアウトに関する情報を管理するクラスです。LineBreakMeasurerから各行のTextLayoutを取り出し、これをもとに描画を行っていきます。

 では、折り返し表示に関する処理部分を順に見ていきましょう。まず、処理に必要となるFontRenderContextと、LineBreakMeasurerを作成します。

FontRenderContext fc1 = g2.getFontRenderContext();
LineBreakMeasurer m1 = new LineBreakMeasurer(ac1,fc1);

 Graphics2DからgetFontRenderContextFontRenderContextを取得します。そして、このFontRenderContextと、あらかじめ用意しておいたAttributedCharacterIteratorを引数に指定して、LineBreakMeasurerインスタンスを作成します。

 これで準備は整いました。いよいよ一切の描画に進みます。次のコードは、LineBreakMeasurerから1行ずつレイアウト・オブジェクトを取り出しては描画する処理を繰り返します。

while (m1.getPosition() < str1.length()) {
    TextLayout tl1 = m1.nextLayout(150);
    tl1.draw(g2, 20, y);
    y += tl1.getBounds().getHeight() + 10;
}

 whileの条件にあるgetPositionは、LineBreakMeasurerで「現在の位置」を示すものです。LineBreakMeasurerは、現在の位置に関する情報を持っており、そこから1行分のレイアウトを取り出すと、その後に現在位置が移動するようになっています。そこで、「現在位置が、テキストの長さより小さい(すなわち、テキスト内のどこかに現在位置がある)間は繰り返す」ようにしているのです。

 繰り返しの中でまず行っているのは、LineBreakMeasurerから「次の行のレイアウト・オブジェクト」を取り出す処理です。これを行っているのがnextLayoutです。引数には、行末までの長さ(幅、ドット数)を指定します。これで、150ドット幅の次行レイアウト・オブジェクトを取り出します。

 取り出されるのは、TextLayoutというクラスのインスタンスです。このTextLayoutdrawメソッドを呼び出すことで、取り出した行のレイアウトをもとに描画を行います。引数には、描画先のGraphics2D、横位置、縦位置を指定します。

 そして描画を行ったら、TextLayoutの領域オブジェクト(getBoundsで取り出されます)から高さ(その行の縦幅)を調べ、これに10を足した値を変数に加算しておきます。これが、次の行の縦位置となるわけです。

 こうして、「次の行のレイアウトを取り出し、描画をしては、描いた行の縦幅を変数に足して描画の縦位置を増やしていく」ということを繰り返していくことで、一定幅で折り返す描画が行える、というわけです。

次のページ
テキストをマウスで選択する

この記事は参考になりましたか?

Swing再入門連載記事一覧

もっと読む

この記事の著者

掌田 津耶乃(ショウダ ツヤノ)

三文ライター&三流プログラマ。主にビギナーに向けたプログラミング関連の執筆を中心に活動している。※現在、入門ドキュメントサイト「libro」、カード型学習サイト「CARD.tuyano.com」を公開...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/2598 2008/06/19 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー