今回からはアプレットの作成を題材に、少々本格的なプログラミングを学んでゆきます。今回の内容は文字や画像を表示するもっとも基本的なアプレットの作成です。また、Javaでプログラミングを行う上で必須の「クラス」と「継承」という考え方も学習します。
5.1 アプレットとは 5.2 文字を表示するアプレット 5.3 「クラス」の考え方と「継承」 5.4 線や図形を描くアプレット 5.5 Graphicsクラスについて 5.6 画像を表示するアプレット
プログラミングの学習をするのに、今までは教育用の特殊環境であるタートルグラフィックスを使ってきました。これは限られた数の命令を用いて効率よく学習できる優れた教材ですが、プログラムとして実現できることは線描を描くことのみでした。もちろんJavaを使ってできることは他にもいろいろあるわけで、その意味では、タートルグラフィックスを用いることは「補助輪」付きの自転車に乗ることと似ています。
今回からはその「補助輪」をはずし、この教室に限らず実際に世界中で用いられている「アプレット」なるものを作ってゆきます。アプレットと聞いて漠然と「動画のあるWebページ」などを思い出す人もいることと思います。一方で、全くはじめて聞くという人もいるかもしれません。そこでとりあえず、現時点ではアプレットに関して最低限次のことを知っておけばいいと思います。
それ以上のことに関しては、今回と次回の講座でプログラムを作成しながら学んでゆきます。
まずはブラウザに「Hello SFC !!」という文字を表示するアプレットを例に、アプレットの作成手順を学んでゆきます。
作成したいのは次のアプレットです。 →サンプル・アプレットへ
それでは早速このアプレットを作ってゆきましょう。アプレット作成の手順は次の通りです。
1 プログラムの作成 2 コンパイル 3 HTMLテキストの作成 4 アプレットの実行
最初にプログラムを記述しましょう。一般的にアプレットのプログラムは次のような書式で記述します。
import java.applet.Applet; // アプレットクラスの読み込み public class MyFirstApplet extends Applet{ ...... // アプレットの中身の記述 } |
タートルの時と同様、一行目には「import」で始まる文を記述します。コメントのところには「アプレットクラスの読み込み」と書かれていますが、この意味は後で説明します(→5.3で説明します)。とりあえずのところ、アプレットを作成する準備だと考えてください。また、2行目の「class」と「extends」の間にはタートルの時と同様、プログラムのファイル名の「.java」以前の部分と一致する名称を記述します。
それでは次に、「Hello SFC !!」という文字を表示させる命令を「//アプレットの中身の記述」の部分に書き込みます。一般的にアプレットにおいて文字や画像を表示する命令はすべて「paintメソッド」を定義し、その中に書き込みます。paintメソッドの定義は次のように行います。
public void paint(Graphics g){ ...... // 命令を記述 } |
仮引数の部分に「Graphics g」と書き込んであります。これは描画を行うための準備ですがその意味は後で説明します。ここでは気にしないで「呪文」として扱ってください。というわけで、これらを組み合わせると次のようなプログラムの枠組みができます。
/* Hello SFC !! を表示するアプレット */ import java.applet.Applet; // アプレットクラスの読み込み import java.awt.Graphics; // グラフィックスクラスの読み込み public class MyFirstApplet extends Applet{ public void paint(Graphics g){ ...... // 命令を記述 } } |
「import」の記述が一行増えていることに注意してください。これは先ほどでてきた「Graphics g」と関連しています。忘れずに記述してください。
さて、最後に「Hello SFC !!」という文字を表示する命令です。一般に文字を表示する命令は次のように記述します。
g.drawString("表示する文字列" , x座標 , y座標); |
表示したい文字の一群(今回は「Hello SFC !! 」、以後このような「文字の一群」のことを文字列と呼ぶ)は「""」で囲みます。またその文字列を表示したい位置(文字のベースラインの開始点)を座標に直し、整数で記述します(次の図を参照)。
座標を数える基準はブラウザの左上隅が(0, 0)で、右横方向にx軸、真下の方向にy軸をとり、ピクセル単位で数えます。ということで、先ほどのサンプルプログラムは「Hello SFC !!」という文字列を(50, 20)の位置に表示しています。従って記述は次のようになります。
g.drawString("Hello SFC !!" , 50 , 20); |
この命令をpaintメソッド中に書き込み、プログラムを完成させます。
/* Hello SFC !! を表示するアプレット */ import java.applet.Applet; // アプレットクラスの読み込み import java.awt.Graphics; // グラフィックスクラスの読み込み public class MyFirstApplet extends Applet{ public void paint(Graphics g){ g.drawString("Hello SFC !!",50,20); // 文字列 Hello SFC!! を表示する } } |
さて、以上でプログラムの本体が完成しました。先ほど示した手順通りこのプログラムをコンパイルして、プログラムと同じディレクトリに「.classファイル(上の例だと"MyFirstApplet.class")」ができていることを確認してください。
このようにして無事にコンパイルが済んだら、今度は「.classファイル」を呼び出すためのHTMLテキストを作成します。たとえば、今作成した"MyFirstApplet.class"を呼び出すためには次のようなテキストを作成します。
<html> <head> <title>My First Applet</title> </head> <body> <applet code="MyFirstApplet.class" width=150 height=150> </applet> </body> </html> |
アプレットを呼び出すために必要なのはappletタグ(6,7行目)です。属性としてcode(呼び出したい「.classファイル」の名前)、width(アプレットの横幅、単位はピクセル)、 height(アプレットの高さ)の三つを指定します。このHTMLテキストを、とりあえず"FirstApp.html"という名前で"MyFirstApplet.class"と同じディレクトリに保存します。
最後に、実際にアプレットを表示してみましょう。Netscapeを立ち上げて"FirstApp.html"をファイルとして指定して開くことで表示できます。また、"MyFirstApplet.class"と"FirstApp.html"の両方をホームディレクトリの下の「public_htmlディレクトリ」におけば、インターネットから見ることもできます。
ところで、ここで先ほど説明を後回しにした「アプレットクラスの読み込み(プログラムの1行目)」の意味について少し掘り下げてみましょう。この記述はどんな意味を持っていて、なぜ必要なのでしょうか?このことを理解するためには、Javaプログラミングにおける「クラス」と「継承」という二つの重要な概念を押さえる必要があります。
まずはじめにクラスとは、ある特定の目的の元で必要となるデータの種類や数と、それを処理するために必要な命令群と手順をあらかじめリストアップし、定義として記述したもののことを指します。少々難しそうな用語ですが、実は先ほど作成した"MyFirstApplet.java"も、また1回目から4回目までに作成してきたタートルグラフィックスの各プログラムも、すべてクラスの定義として作成されています。たとえば"MyFirstApplet.java"では、「文字列"Hello SFC !!"をブラウザ上に表示する」という特定の目的の元で、必要となるデータ及び処理の内容を「paintメソッド」として記述しました。つまり、Javaにおいてプログラムを作成するということはすなわちクラスを定義することなのです。
ひとつひとつのクラスは固有の名前(クラス名)を持っています。プログラムの「public class」の直後に記述する、ファイル名の「.java拡張子」以前の部分がそれにあたります。したがって、プログラム"MyFirstApplet.java"は、「MyFirstAppletクラス」の定義を行ったものだと考えることができます。
ところでこのMyFirstAppletクラスですが、実はすでに用意されている「アプレットの骨組みとなるクラス」を利用することで完成されています。ここで継承という概念が登場します。継承とはあるクラスの定義を元に別のクラスを再定義することをいいます。たとえばアプレットを作成する場合には必ず、アプレットの骨組みとなる Applet という名前のクラスを利用します(このクラスはJavaの実行システムがあらかじめ用意しています)。
この Appletクラスにはアプレットが機能するために必要ないくつかのメソッドがすでに定義されています(paintメソッドもその一つです)。私たちがアプレットを作る際にはこの Appletクラスのメソッドのうち必要なメソッドの中身を記述し直し(上書きして)、また必要ならば新しいメソッドを書き加えて、独立した別のひとつのクラスを作るわけです。何も手直しされない場合、新しいクラスはAppletクラスのメソッドの定義をそのまま引き継ぎます。ちなみに、元となるクラス(アプレットならAppletクラス)を親クラス(スーパークラス)、新しくできるクラス(アプレットならたとえばMyFirstAppletクラス)を子クラス(サブクラス)と呼びます。
一般に、継承を用いてプログラムを作成する場合、必要な手順は次の二つです。
まず、親クラスを読み込むためには、プログラムの本体を記述する前に次のように記述します。
import 読み込みたいクラスの名前; |
たとえば先ほどのMyFirstAppletの場合、Appletクラスを読み込んでおく必要があるわけです。それが例の1行目の「アプレットクラスの読み込み」というコメントをつけた記述なのです。
import java.applet.Applet; |
「読み込みたいプログラムの名前」として指定されている「java.applet.Applet」は、Appletクラスのパッケージ名(Javaがあらかじめ用意するたくさんの「骨組み用プログラム」の分類)を含めた正式な指定の仕方です。
次に、読み込んだクラスを継承することを次のように記述します。
public class これから作成するクラス名 extends 親クラスのクラス名 |
MyFirstAppletでは、プログラムの3行目で次のように記述されています。
public class MyFirstApplet extends Applet |
こうしてAppletクラスを継承しながら、独自のアプレットを作る準備が整ったわけです。あとはAppletクラスを元に独自のクラスを再定義する、という運びになるわけですが、先ほどの説明を整理すると再定義は大きくつぎの二つの仕方で行います。
ただし、これらに関しては今回は深く立ち入りません。MyFirstAppletに関しては、paintメソッドがもともとAppletクラスによって「何かをブラウザに表示・描画するためのメソッド」として漠然と定義されており、我々はそこに「Hello SFC !!という文字列を表示する」という具体的な命令を新たな定義として記述した、というふうに理解しておいてください。
paintメソッド内に先ほどとは異なる命令を記述することで、文字だけでなくいろいろなものをブラウザに表示することができます。たとえば「g.drawString....」の代わりに、
g.drawLine(x1,y1,x2,y2); → x1,y1,x2,y2はそれぞれ整数 |
と記述することで、座標(x1, y1)から座標(x2, y2)を結ぶ直線を描画することができます。そこで、こんなプログラムを作って実行してみましょう。
/** * 200×200ピクセルの領域に * 20ピクセル間隔で縦線を描くアプレット * */ import java.applet.Applet; import java.awt.Graphics; public class Lines1 extends Applet{ // paintメソッドの定義:200×200ピクセルの領域に // 20ピクセル間隔で縦線を描画する public void paint(Graphics g){ int x; for(x=0; x<=200; x=x+20){ g.drawLine(x, 0, x, 200);// 同じ長さの縦線を // x座標を変化させながら // 連続して描く } } } |
HTMLテキストは次のようなものを用意します。
<html> <head> <title>Lines1</title> </head> <body> <applet code="Lines1.class" width=210 height=210> </applet> </body> </html> |
無事に11本の縦線が描画できたでしょうか。 →実行の様子
それではこのプログラムをもとに、今度は200×200ピクセルの領域に格子模様を20ピクセル間隔で描くアプレット Lines2.java を作成してみましょう。 →実行の様子
さて、次は直線ではなく図形を描いてみましょう。たとえば次の命令は、左上角の座標が(x, y)で横の長さがw、縦がhの長方形に内接する楕円を描きます。
g.drawOval(x,y,w,h); |
これを用いることにより、たとえば次のような描画が可能です。 →実行の様子
このアプレットを実現するのは次の記述です。
/** * 中心点が同じ1直線上にあり直径が20ずつ増えてゆく * 5つの円を描くアプレット * */ import java.applet.Applet; import java.awt.Graphics; public class Oval1 extends Applet{ // paintメソッドの定義:中心点が同じ1直線上にあり // 直径が20ずつ増えてゆく5つの円を描画する public void paint(Graphics g){ // g.drawOvalの引数の初期値 int x=0, y=40, w=20, h=20; int i; // 5つの円を描く for(i=1; i<=5; i++){ g.drawOval(x, y, w*i, h*i); x=x+w*i; // x座標の位置 → 外接四角形の一辺の長さを //その都度足してゆく y=y-10; // y座標の位置 → 外接四角形の一辺の長さの // 半分の値をその都度引いてゆく } } } |
文字、直線、楕円などを組み合わせて自分の好きなアプレットを作成しなさい。
ところで、ここまでに作成してきたアプレットのプログラムでは、継承して用いるAppletクラス以外にも、Javaが提供するクラスを読み込んで利用しています。それが2行目のimport文に記述されたjava.awtパッケージの「Graphicsクラス」です。
このクラスがプログラム中に登場するのはpaintメソッドの定義の仮引数のところです。
public void paint(Graphics g) |
仮引数についてはタートルグラフィックスの「部品化」のところで学習していると思います。仮引数は、メソッド名の定義の直後の()内に記されている、「データ型 変数名」という形式の記述です。何らかの仮引数が定義されたメソッドは、そのメソッドが呼び出され利用される際に、仮引数として定義した型のデータを実引数として受け取ります。
これまでの知識に従って記述を素直に読むと、「paintメソッドは仮引数としてGraphics型(?)のデータをgという名の変数に格納する」といった解釈ができます。「Graphics型のデータ」というのが少しばかり釈然としませんが。
実は、このことに関してすべてを解明するには、Javaプログラミング一般に適用される重要な概念について少々込み入った説明をする必要があります。しかしながらここでは、あえて完全な説明は次回に廻し、paintメソッドとGraphicsクラスに関しては次のように理解してください。
変数名.メソッド名(必要な実引数); |
g.drawLine(0, 0, 0, 100);; |
最後に、あらかじめ用意した画像を表示するアプレットを作ります。Javaで扱うことのできる画像は、基本的にはGIFフォーマット及びJPEGフォーマットのものです。
基本的に、画像を表示するためには次の3つのプロセスが必要です。
1 表示したい画像を記憶しておく変数を宣言する 2 プログラムとは異なるファイルに保存される画像のデータを読み込んで、変数の中に格納・記憶する 3 変数の中に保存される画像のデータを表示する
このプロセスのうち3が最終目的であり、1と2はその準備であると考えればわかりやすいでしょう。では、このプロセスをJavaではどのように記述するのでしょうか。
まず「1 表示したい画像を記憶しておく変数を宣言する」は、このように記述します。
Image 変数名; |
Javaにおいて画像は「Image型」として扱われます(→ 但しImageも先ほどのGraphics同様Javaの提供するクラスのひとつです)。変数名は例のごとく自由につけられます。
次に「2 プログラムとは異なるファイルに保存される画像のデータを読み込んで、変数の中に格納・記憶する」ですが、これは次のように記述します。仮にImage型の変数名をimgと宣言したならば、
img = getImage(getDocumentBase(), "画像ファイルのファイル名"); |
これは代入文です。したがって処理は右辺の「getImage」から始まります。この「getImage」はAppletクラスがあらかじめ定義しているメソッドで、画像ファイルのデータをそのファイルのある場所とファイル名を手がかりに探し出し、読み込みます。このメソッドはアプレットの親クラスであるAppletクラスが持っているものなので、利用する際に「 変数名. 」は必要ありません。また引数は最初に「画像の在処」次に「画像ファイルのファイル名」なのですが、「画像の在処」に関しては、画像ファイルとプログラム自身のファイル(.classファイル)を同一のディレクトリに保存しておく限り、上記のように「getDocumentBase()」と書いておけば問題ありません。
つぎに左辺の「img」ですが、これは右辺のgetImageメソッドが実行された結果読み込まれる画像ファイルのデータを左辺の「img」という変数の中に代入し、記憶しておくという意味で書かれています。ここで補足ですが、一般に、あるメソッドを実行した結果、何らかのデータがアウトプットとして返される場合、その返されるデータのことを特に「返値(かえりち)」ないしは「戻り値」と呼びます。これはメソッドをひとつの機械に見立てて考えた場合、メソッドに材料として与えるデータが引数であり、機械が働いた結果生み出されるデータが返値である、と考えることができます。getImageメソッドの場合、「画像の在処」と「画像のファイル名」が引数として与えられると、結果として「Image型のデータ」が返値として返され、それが左辺のimgにに代入されるわけです。
最後に「3 変数の中に保存される画像のデータを表示する」ですが、これはGraphicsクラスの「drawImageメソッド」を用いて次のように記述します。たとえばGraphicsクラスの変数名を「g」、画像を代入したImage型の変数名を「img」とするなら、
g.drawImage(img,x, y, this); → 但しx,yは整数の値 |
このメソッドは4つの引数をとります。まずは画像を代入したImage型の変数名、次の二つは表示位置の座標、をそれぞれ記述します。そして最後の「this」はとりあえず呪文として必ず記入しておいてください。
さて、これらすべてをpaintメソッドの中に記入し、先頭のimport文をひとつ増やせば画像を表示するプログラムがひとまず次のように完成します。
/** * 「マンボウ」の画像を表示するアプレット **/ import java.applet.Applet; import java.awt.Graphics; import java.awt.Image; public class Manbou extends Applet{ public void paint(Graphics g){ // 画像のタイトルを表示する g.drawString("Hi, Manbou is my name !", 50, 10); // 画像を記憶する変数を宣言する Image img; // 画像を読み込む img = getImage(getDocumentBase(), "manbou.gif"); // 画像を表示する g.drawImage(img, 50, 20, this); } } |
読み込んだ二つの画像を交互に表示するアプレット DrawImg.javaを作成しなさい
→ 問題の実行結果
>> 目次ページへ