Java Applet の作り方

文字を描く

前回,基本的なグラフィックのやり方を説明しましたが,文字を書くところはちょっとややこしいので説明をしようと思います.

文字列を表示するのに使うのはGraphicsクラスのdrawString(String str, int x, int y)でいいのですが, これでは文字の種類と描く位置(直接指定するのはベースラインの開始位置)しか指定できません(あと,前回やった色), 大きな文字を書きたいとかイタリックにしたいとかフォントを変えたいってときはどうするのかというと, GraphicsクラスのsetFont(Font f)というメソッドを使います(デフォルトのフォントを指定する場合はAppletクラスのsetFont()を利用する). 色の指定と同様に,Fontクラスを使ってフォントを指定します.

Fontクラス

フォントクラスはどうやって作るのかというと,コンストラクタを見れば分かりますが,Font(String name, int style, int size) となっており,フォントの名前フォントのスタイルフォントのサイズで指定します.
フォントの名前っていうのは,MSゴシックなどを指定すればいいのですが, こういう具体的な名前(物理フォント)を指定すると違うプラットホームではフォントの指定が出来なくなってしまいます. Appletはブラウザなどのユーザプラットホームで実行されるモノなので,こういったことは気をつけなければなりません(自分のところで動けばいいってモノではない). では,どうするかというと,フォントファミリーを指定します(Javaでは論理フォントと呼んでいる). これはどのような特徴を持ったフォントなのかという漠然とした指定で, 各プラットホームごとに適切なフォントが割り当てられます. Javaで使用できるフォントファミリー名はDialog,DialogInput,Monospaced,Serif,SansSerifの5つのうちのいずれかです. この5つは必ず何らかの物理フォントにマップされていることが保証されています.ただし,指定によって違うフォントになることは保証されない. また,この名前にnullを指定するとデフォルトのフォントが指定されたことになります.
フォントのスタイルは,FontクラスのスタティックフィールドのPLAIN,BOLD,ITALICを使用して指定します. BOLDとITALIC両方を指定する場合,2つのビット結合BOLD|ITALICを指定します.
フォントサイズはポイント数で指定します.

というわけで,いろんなフォントを指定して表示してみましょう.

import java.applet.*;
import java.awt.*;

public class Text1 extends Applet {
  public void paint(Graphics g) {
    g.drawString("English 日本語",10,10);
    g.setFont(new Font(null,Font.PLAIN,32));
    g.drawString("English 日本語",10,40);
    g.setFont(new Font("Serif",Font.ITALIC,32));
    g.drawString("English 日本語",10,70);
    g.setFont(new Font("Monospaced",Font.BOLD,32));
    g.drawString("English 日本語",10,100);
    g.setFont(new Font("DialogInput",Font.ITALIC|Font.BOLD,32));
    g.drawString("English 日本語",10,130);
  }
}

さて,これである程度好きな文字が書けるようになりました.
ところで,このフォントを使った文字描写の場合,環境によってフォントが異なる可能性があり, 作っている側から,あらかじめフォントの正確な大きさなどを知るのは難しいです. だからというわけでもありませんが,実際に描画領域がどうなるのかなどの情報を正確に取得する方法があります. 次はその方法について説明しますが,その前に2次元座標などの情報を扱うクラスについて説明します.

2次元空間のデータクラス

2次元グラフィックの場合,座標のx,yや高さと幅など,ベクトルや数字の組み合わせをよく扱います. こういった値をまとめて扱うためのクラスが用意されています.
これらは結構重要でメソッドの戻り値などにも利用されます. たとえば,Appletのサイズを知るにはgetSize()というメソッドを使ってDimensionクラスを取り出します.
そのほかにも,自分でメソッドを作った際の値の受け渡しや, 内部変数の保持などに利用すると便利です. (何となく使ってるだけでそれっぽいプログラムに見えるって言う利点(?)もあり(笑))

java.awt.Point

整数の2次元の座標(x,y)を格納します.java.awt.geom.Point2Dを継承したクラスです. 実数座標を用いる場合はjava.awt.geom.Point2D.Doubleやjava.awt.geom.Point2D.Floatを用います.(いずれもjava.awt.geom.Point2Dのインナークラス)
パブリックフィールドのx,yが利用できるので,C言語の構造体のようにも利用できます. フィールドのx,yはint型ですが,getX(),getY()メソッドによって得られる値はdouble型であることに注意.

java.awt.Dimentsion

整数の高さと幅の組み合わせの値(width,height)を格納します.java.awt.geom.Dimension2Dを継承したクラスです. 実数のサイズを用いる場合はjava.awt.geom.Dimension2D.Doubleやjava.awt.geom.Dimension2D.Floatを用います.(いずれもjava.awt.geom.Dimension2Dのインナークラス) 実際の大きさを表現するクラスなのでwidth heightは非負の値である必要があります. 負の値を設定することは可能ですが,このクラスをサイズとしてAPIに渡したときの動作は保証されません. このクラスもパブリックフィールドのwidth heightでアクセス可能です. フィールドのwidth,heightはint型ですが,getWidth(),getHeight()で得られる値はdouble型です.

java.awt.Rectangle

矩形領域を表す整数の左上の点の座標と幅,高さを格納するクラスです.上記のPointとDimension両方の情報を格納しています. getLocation()でPointクラス,getSize()でDimensionクラスを得ることが出来ます. 同様にjava.awt.geom.Rectangle2Dを継承しており,その実数系はインナークラスであるjava.awt.geom.Rectangle2D.Double java.awt.geom.Rectangle2D.Floatが用いられます. また,パブリックフィールドとメソッドの関係も同様です.

FontMetricsクラス

では,Fontの情報ですが,これはFontMetricsクラスを利用して取得できます. このクラスは直接インスタンスを生成できず,GraphicsクラスのgetFontMetrics()というメソッドを使って取得します.
さて,このFontMetricsクラスを用いると,ある文字の幅を知ったり,1行の高さなど,いろいろな情報を取得できます.
以下は,getStringBoundsを利用して,文字列の表示領域を取得する例です.
ちなみに,getStringBoundsで取得できるDimension2Dは実体はDimension2D.Floatで, x,yの座標はGraphicsクラスのdrawStringで指定した座標を原点としたときの文字表示領域の左上の座標です.

import java.applet.Applet;
import java.awt.*;
import java.awt.geom.*;

public class Text2 extends Applet {
  private static final String str = "English 日本語";
  private static final Point  pt  = new Point(10,60);
  public void init() {
    setFont(new Font(null, Font.PLAIN, 48));
    setBackground(Color.GREEN);
  }
  public void paint(Graphics g) {
    FontMetrics fm = g.getFontMetrics();
    //srtを書いたときの領域を取得
    Rectangle2D r = fm.getStringBounds(str,g);
    g.setColor(Color.WHITE);
    //文字領域を塗りつぶし
    g.fillRect((int)r.getX() + pt.x, (int)r.getY() + pt.y,
               (int)r.getWidth(), (int)r.getHeight());
    g.setColor(Color.BLACK);
    g.drawString(str, pt.x, pt.y);
    g.setColor(Color.BLUE);
    //文字領域を囲む
    g.drawRect((int)r.getX() + pt.x, (int)r.getY() + pt.y,
               (int)r.getWidth(), (int)r.getHeight());
    g.setColor(Color.RED);
    //ベースラインを引く
    g.drawLine(pt.x, pt.y, (int)r.getWidth() + pt.x, pt.y);
  }
}

これは,まず,表示したいフォントで文字列を表示したときの領域を取得し,その領域を白に塗りつぶし, 実際に文字列を描写,そして,その領域の輪郭を描き, ベースライン(drawStringで指定したy軸)がどこにあるのかを示すために線を引きました.

どうでしょう?これで,文字を使ったグラフィックも出来るようになったと思います.
では,また次回〜〜

JavaAppletの作り方
第1回  基本事項 2004/09/25更新
第2回  何もしないアプレット 2004/09/25更新
第3回  静止画グラフィック 2004/09/26更新
第4回  文字を描く 2004/09/27更新
第5回  情報取得 2004/09/28更新
第6回  アニメーション 2004/09/29更新
第7回  アニメーションの改善 2004/09/30更新
第8回  マウス・キーボードを使う(1) 2004/10/03更新
第9回  マウス・キーボードを使う(2) 2004/10/05更新
第10回 マウス・キーボードを使う(3) 2004/10/08更新