さて、今日は早速、プログラミングに入ります。
開発環境はMac OSX 10.6.5
Eclipse 3.6 Helios (日本語化パッチ適用)
MacでEclipseを日本語化するにあたってこのサイトを参考にしました。
とてもわかりやすかったです。
ウィンドウの作成
import java.awt.Insets;
import javax.swing.JFrame;
public class Chap3Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO 自動生成されたメソッド・スタブ
new Chap3Main();
}
JFrame mainwindow;
//コンストラクタ
public Chap3Main(){
this.mainwindow = new JFrame("初めてのウィンドウ");
this.mainwindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.mainwindow.setVisible(true);
//ウィンドウサイズ設定
Insets in=this.mainwindow.getInsets();
this.mainwindow.setSize(480 + in.left + in.right ,360 + in.top + in.bottom);
}
}
・パッケージ名を指定していないとクラスライブラリで定義されているクラス名がわからない。
・パッケージ名はクラスの名字のようなもの javax.swing.JFrame mainwindow;
・パッケージ名.クラス名;というインポート文を書くと、ソースコードの中でパッケージ名を省略できるようになる。
・Ctrl(Macはcommand)+Shift+Oでインポートの編成処理が行われ、必要なインポート文が追加され、
不要なインポート文は削除される。
・static修飾子を付けて宣言したメソッドは、インスタンスを作る前でも呼び出せるスタティックメソッド
(クラスメソッドとも呼ぶ)になる。
mainメソッドはこのしくみを利用してインスタンス作成前にOSから呼び出されるので、
内部でインスタンスを作らなければいけない。
・クラス名と同じ名前のメソッドをコンストラクタ(建設者の意味)という。
・コンストラクタはインスタンスが作られるときに呼び出される。
・コンストラクタの中ではインスタンス作成直後のさまざまな初期化を行う。
・Chap3MainクラスのコンストラクタではJFrameのクラスのインスタンス作成〜表示までの処理を行う。
・JFrameクラスのインスタンスを作成し、mainwindowフィールドに代入。
・JFrameクラスのコンストラクタは引数の文字列をウィンドウのタイトルにする。
・ウィンドを閉じると同時にプログラムを終了するには、
JFrameクラスのsetDefaultCloseOperetionメソッドの引数にEXIT_ON_CLOSEを指定する。
・このEXIT_ON_CLOSEは定数。安徽しにくい数値を覚えやすくするたみに使う。
・setDefaultCloseOperation(3)よりsetDefaultCloseOperation(EXIT_ON_CLOSE)の方が意味がわかりやすい。
・ウィンドウは初期設定では非表示になっているため、setVisibleメソッドでtrueを指定して表示。
・ウィンドウサイズはJFrameクラスのsetSizeメソッドで設定できるが、
ここで指定したサイズにはウィンドウ枠とタイトルの文が含まれている。
・クライアントエリアを480×360ピクセルにするには枠やタイトルバーの太さを加えたサイズを指定。
・ウィンドウの四辺のサイズはJFrameクラスのgetInsetsメソッドで調べることができる。
このメソッドはInsetsクラスのインスタンスを返すので、その4つのフィールド
top , bottom , left , right を480×360ピクセルに加える。実行するとウィンドウが表示される。
リアルタイム処理
・コンピュータに時間を計らせて、一定の時間ごとに同じ量の仕事をやらせることをリアルタイム処理という。
・Javaでリアルタイム処理を実現するには、TimerクラスとTimerTaskクラスをセットで使う。
・処理をrunメソッドに書いておき、Timerクラスが一定間隔でrunメソッドを呼び出すしくみ。
・Timerクラスは指定された間隔でTimerTaskクラスのrunメソッドを呼び出す。
・処理はrunメソッドの中に書けばよいが、TimerTaskクラスを直接書き換えることはできない。
(Javaのクラスライブラリの中で定義されているため)
・このような場合TimerTaskクラスを継承したクラスを作成し、runメソッドの内容を書き換える。
・継承とはすでにあるックラスを引き継いで新しいクラスを作成すること。
・元になるクラスをスーパークラス、継承して新しく作られるクラスをサブクラスと呼ぶ。
・フィールドもメソッドも丸ごと引き継がれるので、必要な部分を書き足すだけで済む。
・継承するにはサブクラスの定義にextendsキーワードを加える。
・クラスの中に書かれたクラスを内部クラス(またはインナークラス)と呼ぶ。
・TimerTaskクラスを継承したクラスには必ずrunメソッドを書かなければいけないという決まりがある。
・サブクラスに絶対に書かなければいけないメソッドのことを抽象メソッドと呼ぶ。
・Ctrl(Macではcommand)+Shift+Mで現在カーソルがあるクラスのインポート文を自動挿入できる。
・インポート文をまとめて挿入するCtrl+Shift+Oが便利だが、ソースコード中にその他のエラーがあると働かない。
・Ctrl+Shift+Mはエラーがある時でも使える。
・スーパークラスと同じ名前と型のメソッドを書くことをオーバーライドという。overrideとは上書きの意味。
import java.awt.Insets;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
public class Chap3Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO 自動生成されたメソッド・スタブ
new Chap3Main();
}
JFrame mainwindow;
// コンストラクタ
public Chap3Main() {
this.mainwindow = new JFrame("初めてのウィンドウ");
this.mainwindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.mainwindow.setVisible(true);
// ウィンドウサイズ設定
Insets in = this.mainwindow.getInsets();
this.mainwindow.setSize(480 + in.left + in.right, 360 + in.top
+ in.bottom);
//タイマー作成
Timer t=new Timer();
t.schedule(new GameTask(),0, 500);
}
class GameTask extends TimerTask{
@Override
public void run() {
// TODO 自動生成されたメソッド・スタブ
System.out.println("呼び出された");
}
}
}
このプログラムを実行すると0.5秒ごとに「呼び出された」という文字がコンソールに表示される。
・Timerクラスのscheduleメソッドでは引数periodに呼び出し間隔を指定する。
・単位はミリ秒。1秒=1000ミリ秒なので、500を指定すると0.5秒間隔で呼び出されることになる。
public void schedule (TimerTask task, long delay, long period)
・task→Timerから呼び出すTimerTaskインスタンスを指定
・delay→最初の呼び出しを実行するまでの遅延時間をミリ秒で指定
・period→runメソッドを呼び出す間隔をミリ秒で指定
・継承のメリット
すでに作ったクラスの機能を流用できること
スーパークラス型の変数・引数にサブクラスのインスタンスを代入できること
scheduleメソッドの引数taskはTimerTask型なのに、GameTaskクラスのインスタンスを指定できている。
サブクラスはスーパークラスの全てのフィールドとメソッドを持っている。
スーパークラスだと思って扱っても問題ない。
人間や動物の世界では親のできることを子供が必ずできるとは限らないが、
コンピュータの世界ではそれが保証されている。
逆にサブクラス型の変数・引数にスーパークラスのインスタンスを代入することはできない。
(無理にすることはできるが危険)
※サブクラスで追加したフィールドやメソッドを要求されたときにスーパークラスは対応できないため
・オーバーライド
スーパークラスのメソッドをサブクラス側で上書きすること。
同じようにメソッドを呼び出しても違う処理を行うことが可能。
オーバーライドするにはメソッドの名前と引数・返り値の型を同じにしなければならない。
どれかが違っていると新しいメソッドを追加したことになる。
オーバライドミスを避けるためにオーバーライドしたメソッドの直前に@Overrideと書く。
このキーワードがあるとJavaコンパイラーがスーパークラスに同名同型メソッドがあるか確認し、
なければ、エラーを表示してくれる。
・抽象メソッド
その名のとおり定義のブロックがない。abstract修飾子をつけて、型と名前を指定したら;を付けて終わりにする。
このメソッドを必ずオーバーライドしてねと予約しておくのが抽象メソッドの役割。
public abstract void run(); //抽象メソッドには定義ブロックがない
抽象メソッドを持つクラスはインスタンスが作れない抽象クラスになる。中身が空のメソッドは実行しようがない。
抽象クラス・抽象メソッドは継承されることが前提の文法である。
・内部クラス
特定のクラスからしか利用されないことが決まっているときに使う。
GameTaskクラスのrunメソッドはChap3Mainクラスからしか利用できない。
できればChap3Mainクラスの中で定義したいくらい。
それなのにわざわざ別のソースコードに分けて書くのは面倒なので内部クラスにしている。
内部クラスは役に立つ居候、お腹の中のビフィズス菌のような存在。
外側のクラス(外部クラス)のフィールド・メソッドを自分のメンバと同じように利用できる。
public class Outer {
int field0;
void method0{
}
class Inner{
field0=10;
method();
}
}
//内部クラスは外部クラスのメンバを自由に利用できる。
逆に外部クラスから内部クラスのフィールド・メソッドを利用するときは、
内部クラスのインスタンスを内部クラス型フィールドに代入して予備ださなければいけない。
なぜなら、内部クラスにとって外部クラスは1つしかないが、
外部クラスの中に複数の内部クラスを入れることは可能なので、区別擦る必要があるからである。
・メソッドのオーバーロード
overloadとは引数や返り値の型が違う同じ名前のメソッドを定義すること。
たとえばprintメソッドを入力するとprint(boolean b) print(char c)などの候補がたくさん表示されるが、
これはprintメソッドがオーバーロードされているから。メソッドを使う側からすると、
1つのメソッドに色々な種類のデータを渡せるように見える。
なお、オーバーロードとオーバーライドは名前がよく似ているが全く別の文法なので、間違わないよう注意。
画像ファイルの読み込み、表示
・画像ファイルや音楽ファイルなどを読み込む場合、
それらのファイルをプログラムファイルの外部に置く方法とプログラムファイルの中に含める方法が考えられる。
プログラムファイル内に含められたファイルをリソースと呼ぶ。resourceは資源という意味。
webでの取り扱いを楽にするために、すべてリソースにすることにする。
画像ファイルや音楽ファイルをリソースにするにはパッケージエクスプローラーで
パッケージ内にファイルをインポートする。
インポート完了後、ImageIOクラスのreadメソッドを使って画像ファイルをメモリに読み込む。
IOはInput/Outputの略。入力と出力の意味→読み込み、書き込みのこと。
ImageIOではPNG、GIF、JPEG形式の画像ファイルを読み込むことができる。
大きめの画像には圧縮率が高いJPEG、ゲームのキャラクタには透明職を設定できるPNGが向いている。
readメソッドはFileやInputStream、URLなどの型の引数を受け取って、
BufferredImageクラスのインスタンスを返す。
HDD上のファイル、インターネット上のファイルを読み込む場合は次のように書く。
BufferedImage bimage;
//HDDから↓
bimage= ImageIO.read(new File("画像ファイル名"));
//ネットから↓
bimage= ImageIO.read(new URL("http://~.co.jp/画像ファイル名"));
//リソース↓
bimage = ImageIO.read( this.getClass() .getResource("画像ファイル名"));
リソースを読み込む場合が一番ややこしくなっている。
リソースを読み込むにはgetResourceメソッドを使うが、このメソッドはClassクラスのメンバである。
Classクラスはクラスに関する情報を管理するクラスで、すべてのクラスが持つgetClassというメソッドで取得する。
これらの処理をひとつなぎで書くと、
this.getClass().getResource("リソース名"));
となる。
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class Chap3Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO 自動生成されたメソッド・スタブ
new Chap3Main();
}
JFrame mainwindow;
BufferedImage img_back;
// コンストラクタ
public Chap3Main() {
this.mainwindow = new JFrame("初めてのウィンドウ");
this.mainwindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.mainwindow.setVisible(true);
// ウィンドウサイズ設定
Insets in = this.mainwindow.getInsets();
this.mainwindow.setSize(480 + in.left + in.right, 360 + in.top
+ in.bottom);
//画像読み込み
try {
this.img_back = ImageIO.read(this.getClass().getResource("IMG_0338.JPG"));
} catch (IOException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
//タイマー作成
Timer t=new Timer();
t.schedule(new GameTask(),0, 500);
}
class GameTask extends TimerTask{
@Override
public void run() {
// TODO 自動生成されたメソッド・スタブ
Graphics g= mainwindow.getGraphics();
g.drawImage(img_back, 8, 29, mainwindow);
g.dispose(); //描画終了
}
}
}
これを実行するとこんな感じ↓そろそろ時間なので、今日はここまで。