図を描こう
Graphicsクラスを使いこなす
前回はAppletクラスのスーパークラスで定義されているpaint()メソッドについて学習しました
paint()メソッド内で、Graphicsクラスを使って文字を出力させましたね
今回は、このGraphicsクラスのメソッドをより詳しく取り上げましょう
このクラスを使いこなすことによって、図を簡単に出力することができます
まず、ウィンドウに線を書いてみましょう
なんてことはない、単なる線を一本だけ描いてみます
線を描くにはdrawLine()メソッドを使用します
public abstract void drawLine( int x1, int y1, int x2, int y2 )
x1とy1は、線の開始x座標とy座標です
x2とy2は、線の終点のx座標とy座標です
import java.applet.Applet;
import java.awt.Graphics;
/*<applet code="App2.class" width="400" height="200"></applet>*/
public class App2 extends Applet {
public void paint(Graphics g) {
g.drawLine( 0 , 0 , 400 , 200 );
}
}
これは、簡単ですね
次に長方形を描こうと思います
基本的には、drawLine()の調子でポポンと描いてしまいたいのですが
ちょっとした注意点があります
まず、長方形の線(外枠)を描くにはdrawRect()を使用します
現在の色(グラフィックコンテキスト)で塗りつぶされた長方形を描く時はfillRect()を使います
public void drawRect( int x, int y, int width, int height )
public abstract void fillRect( int x, int y, int width, int height )
この二つのメソッドの引数の意味は、両方とも同じです
ただ、fillRectは中を色で塗りつぶすというだけにすぎません
xとyは、予想どうりコンポーネント内の開始座標 xとyです
しかし、widthとheightは終点の座標ではないことに注意しましょう
widthとheightは開始座標からのサイズを指定するものです
たとえば、g.drawRect(10 , 10 , 100 , 100) というように指定した場合
一見すると10×10の位置から100×100までの長方形をイメージしますが違います
これは、開始座標10から100進んだ位置までという意味です
結果、左上の位置を10×10として110×110の位置を右下とした長方形が出力されます
細かな計算を必要とする正確なグラフィック操作では、このような誤差は許されません
import java.applet.Applet;
import java.awt.Graphics;
/*<applet code="App3.class" width="400" height="200"></applet>*/
public class App3 extends Applet {
public void paint(Graphics g) {
g.drawRect(50 , 20 , 300 , 160);
g.fillRect(70 , 30 , 260 , 140);
}
}
いい感じですね
さらに円を描いてみましょう
Javaは円もメソッドで簡単に描くことができます
円を出力するにはdrawArc()を使用します
このメソッドは円の外枠を出力します。塗りつぶしにはfillArc()を使用します
public abstract void drawArc( int x, int y, int width, int height, int startAngle, int arcAngle )
public abstract void fillArc( int x, int y, int width, int height, int startAngle, int arcAngle )
ぬお!?なんじゃこの引数は
と思うかもしれませんが、なんてことはありません
第四引数までは長方形を描くdrawRect()とまったく同じです
円は指定された長方形に納まります
startAngleには開始角度を指定し、arcAngleは終了角度を指定します
Arcは角度を指定できますが、楕円の場合はdrawOval()でもかまいません
もちろんこちらにも、塗りつぶすタイプのfillOval()があります
public abstract void drawOval( int x, int y, int width, int height )
public abstract void fillOval( int x, int y, int width, int height )
Oval()の場合は円が納まる長方形だけを指定します
この長方形の指定はdrawRect()とおなじなので、引数の説明は不要でしょう
次のプログラムを見れば、その関係が明らかです
import java.applet.Applet;
import java.awt.Graphics;
/*<applet code="App4.class" width="800" height="200"></applet>*/
public class App4 extends Applet {
public void paint(Graphics g) {
g.drawArc(10 , 10 , 180 , 180 , 30 , 240);
g.fillArc( 210 , 10 , 180 , 180 , 0 , 300);
g.drawRect(410 , 10 , 180 , 180);
g.drawOval(410 , 10 , 180 , 180);
g.fillOval(610 , 10 , 180 , 180);
}
}
左二つがArc、残り右二つがOvalです
drawArc()などでも、当然角度を0と360に指定すれば同じ円を書くことができます
わかりやすいように、一ヶ所だけ長方形を書いてみました
drawRect()の引数の内容と、drawOval()の内容が同じですね
つまり、円が長方形に納まっているということです
高度な図形
さらに高度な図形を描くのに、多角形を出力することもできます
多角形を描くのには、int型の配列を利用することで簡単にかつ効率的に描けます
多角形にはdrawPolygon()を使用します
このメソッドは、最後のラインにたどり着くと最初の位置にラインを引くことで閉じます
そうではなくて、ラインだけを連続的に引いて閉じない場合はdrawPolyline()があります
drawPolygon()と違うのは、始点と終点がと異なっていても閉じないということです
Polygon()メソッドには、多角形の中を塗りつぶすfillPolygon()メソッドがあります
public abstract void drawPolygon( int xPoints[], int yPoints[], int nPoints )
public void drawPolygon( Polygon p )
public abstract void fillPolygon( int xPoints[], int yPoints[], int nPoints )
public void fillPolygon( Polygon p )
public abstract void drawPolyline( int xPoints[], int yPoints[], int nPoints )
それぞれ、xPoints[]にはx座標の値が格納されているint型の配列
yPoints[]にはy座標の値が格納されているint型の配列を指定します
nPointsは線の数を指定します
つまり、x,yの配列が5ヶ所の点を表している場合は5を指定します
配列の最後尾ではなく角の数の指定であることに注意してください
配列の数よりも少ない値を指定しても問題ありません。ただし負数を指定すると例外が発生します
Polygon p はPolygonクラスのオブジェクトを渡します
Polygonクラスはこのような多角形の情報をカプセル化しているクラスです
Polugonクラスの詳細は示しませんが、このクラスのコンストラクタは次の二通りです
public Polygon()
public Polygon( int xpoints[], int ypoints[], int npoints )
上は空の多角形を作成します
もう一方の下のコンストラクタの引数は、drawPolygon()メソッドと同じ事に気づくと思います
このコンストラクタは、drawPolygon()同様に指定します
PolygonクラスのオブジェクトをdrawPolygon()メソッドが受け取った場合はそのオブジェクトの多角形を出力します
次のプログラムでそれぞれのメソッドを実行しています
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Polygon;
/*<applet code="App5.class" width="450" height="200"></applet>*/
public class App5 extends Applet {
public void paint(Graphics g) {
int x[] = { 10 , 40 , 80 , 50 };
int y[] = { 10 , 180 , 100 , 30 };
g.drawPolygon(x , y , 4);
ary(x);
g.fillPolygon(x , y , 4);
ary(x);
g.drawPolygon(new Polygon(x , y , 4));
ary(x);
g.fillPolygon(new Polygon(x , y , 4));
ary(x);
g.drawPolyline(x , y , 4);
}
void ary(int x[]) {
int count;
for (count = 0 ; count < 4 ; count++) x[count] += 80;
}
}
drawPolygon()とfillPolygon()メソッドは、直接多角形を指定する方法と
Polygonクラスのオブジェクトを渡す二種類の方法を試しています
drawPolyline()メソッドの結果は一番右の図です
最終ラインで閉じられることなく途切れているのがわかりますね
配列は、多角形の各地点を表しています
最初の始点が x[0] , y[0] の座標です
その後、指定された回数だけ点をつけてそれを結んでいます
最後に、角の丸い長方形の作り方を覚えましょう
これはdrawRoundRect()を使います
もちろん、長方形の中を塗りつぶすfillRoundRect()も存在します
public abstract void drawRoundRect( int x, int y, int width, int height, int arcWidth, int arcHeight )
public abstract void fillRoundRect( int x, int y, int width, int height, int arcWidth, int arcHeight )
第四引数まではdrawRect()と同じです
arcWidthは、各端の丸くする横サイズを指定し
arcHeightは、同様に丸くする縦のサイズを指定します
import java.applet.Applet;
import java.awt.Graphics;
/*<applet code="App6.class" width="400" height="200"></applet>*/
public class App6 extends Applet {
public void paint(Graphics g) {
g.drawRoundRect(10 , 10 , 180 , 180 , 50 , 50);
g.fillRoundRect(210 , 10 , 180 ,180 , 100 , 50);
}
}
意外な落とし穴
じつは、draw...とfill...の間には意外な違いがあります
リファレンスには draw 系メソッドの働きを「外枠」と表現していますが
fill 系のメソッドと比較して、この「外枠」には深い意味があります
なんと draw. ..で描かれた外枠の図形と
fill...で塗りつぶされた図形は1ピクセルの差があるのです
この1ピクセルの差を知らない場合
外枠と中を別の色で表現した図形などで苦労することになるでしょう
たとえば、まったく同じ大きさを指定したdrawOval()とfillOval()を見比べてください
次のプログラムで、1ピクセルの差を見つけることができます
import java.applet.Applet;
import java.awt.Graphics;
/*<applet code="App7.class" width="400" height="200"></applet>*/
public class App7 extends Applet {
public void paint(Graphics g) {
g.drawRect(10 , 10 , 181 , 181);
g.fillOval(10 , 10 , 180 , 180);
g.drawRect(210 , 10 , 181 , 181);
g.drawOval(210 , 10 , 180 , 180);
}
}
左側の塗りつぶした円( fillOval() )は、右の円( drawOval() )と比べて
わずかな差があるのがわかりますね
長方形drawRect()は、左、右ともに同じサイズです、が
円の右側と下部分に、塗りつぶしている円は1ピクセルほどの空白があります
これが1ピクセルの差です