-1- 【Step2 を始める前に】 音声が鳴るかどうかを確かめます。 手順 1.共有フォルダにあるSoundTest.jar を適当な場所にコピー 2.PC のミュートを外す。 3.ディスプレイのボリュームボタンを0 以上にする。 4.コピーしたSoundTest.jar をダブルクリック 5.「サウンド再生1」をクリックしてみる。 6.5で鳴らなかったら、「サウンド再生2」をクリックしてみる。 7.6でも鳴らない人は教官に確認して、PC を移動してみて下さい。 ※移動の際にはボリュームをOFF にしていく
6で初めてなった人は、Step2 の MainPanel.java の play メソッドをテキストの通りではなく、以下の ように書いてください。 /** * 音声再生メソッド * @param index * @throws Exception */
private void play(int index) throws MyException { try {
// オーディオ入力ストリームを取得
AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFiles[index]); // オーディオ形式を取得
// AU、AIFF、WAVE形式に対応している
AudioFormat format = audioStream.getFormat(); // データラインの情報(フォーマットなど)を作成
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); // データラインの情報オブジェクトを生成
SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info); // ラインを開く line.open(format); // ラインでのデータ入出力を可能にする line.start(); int nBytesRead = 0; int EXTERNAL_BUFFER_SIZE = 128000;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE]; while (nBytesRead != -1) {
// オーディオストリームからデータを読み込み
nBytesRead = audioStream.read(abData, 0, abData.length); if (nBytesRead >= 0) { // オーディオデータをミキサーに書き込み line.write(abData, 0, nBytesRead); } } // ラインからキューに入っているデータを排出 line.drain(); // ラインを閉じる line.close(); } catch (Exception e) {
throw new MyException("再生失敗:"+e.getMessage(), e); }
-2-
【
Animals サンプル Step 2】
張り付けた動物の上をクリックすると、それぞれの鳴き声で鳴く。 <例外について> エラーや、通常の処理の中では起こってはいけない事象のことを例外といい、例外が起こる可能性が ある場合はその対応処理を記述しなければならない。一般に、java.lang パッケージの Exception という クラスやそのサブクラスを使って次のように記述する。 ※Error というクラスもあるが、これは、メモリ不足などアプリケーションにとって非常に重大な問題 のことで、例外処理では復旧できないため、記述されない。 int i = 0; try { int j = 1 / i ; // 0 で除算はできないので例外発生 System.out.println(“例外が発生するとこの行には到達しません。”); } catch (Exception e) { e.printStackTrace(); // 例外に関する情報を出力する } 上の例で、int 型の変数 i は 0 で初期化されているので、j を計算することはできず、Exception のサブ クラスである ArithmeticException というクラスのオブジェクトが発生する。例外が発生すると、その 後の行は実行されることなく、catch ブロックの中へとんで、プログラムは終了する。したがって、上の 例ではi に他の値を入れない限り System.out~の行は実行されない。 例外Exception と関連の深いクラスの親子関係は以下の図であらわされる。 <作成手順> ※説明のためにコメントが多くあるが、必要以上書かなくてよい 1.RuntimeException のサブクラスとなる MyException を作成 ※本来はException の直接のサブクラスとするべきだが、ツールのプレビュー表示にエラーが出る のでRuntimeException にする animals パッケージを選択→新規→クラスを選択 ・名前は「MyException」 ・スーパークラスの参照をクリックし、「RuntimeException」の入力で出てくるクラスを選んで OK ・「スーパークラスからのコンストラクタ」にチェックをいれて「完了」 必要な記述はすべてEclipse が書いてくれるので、特に記述することはない。 2.MainPanel クラスのソースに追加記述(※MainPanel.java を参照) 3.AnimalsFrame クラスのソースに追加記述(※AnimalsFrame.java を参照) 4.実行する ・・・・ Throwable Exception Error ・・・・ ・・・・ ・・・・ RuntimeException ・・・・ ・・・・MyException.java -3- package animals; 1 2 /** 3 * このアプリ固有のException<br> 4 * Exceptionが出た場合に、原因を限定しやすいので 5 * すでにJavaにあるクラスExceptionを継承して作る。<br> 6 * ここでRuntimeExceptionというのは例外処理を必要としない特殊なExceptionなので、 7 * 本当はRuntimeExceptionでなくExceptionの直接のサブクラスでつくるべきだが、 8 * ツールのプレビュー表示にエラーが出るのでRuntimeExceptionにしている。 9 */ 10
public class MyException extends RuntimeException { 11 12 /** 13 * 引数なしのコンストラクタ 14 */ 15 public MyException() { 16 } 17 18 /** 19 * コンストラクタその1<br> 20 * メッセージを設定する 21 * @param message 22 */ 23
public MyException(String message) { 24 super(message); //親クラスのコンストラクタの呼び出し 25 } 26 27 /** 28 * コンストラクタその2<br> 29 * 原因となったエラーを設定する 30 * @param cause 31 */ 32
public MyException(Throwable cause) { 33 super(cause); 34 } 35 36 /** 37 * コンストラクタその3<br> 38 * メッセージと原因となったエラーを設定する 39 * @param message 40 * @param cause 41 */ 42
public MyException(String message, Throwable cause) { 43 super(message, cause); 44 } 45 46 } 47
MainPanel.java -4- package animals; 1 2 import java.awt.Graphics; 3 import java.awt.Graphics2D; 4 import java.awt.SystemColor; 5 import java.awt.event.MouseEvent; 6 import java.awt.event.MouseListener; 7 import java.io.File; 8 import java.util.ArrayList; 9 import java.util.List; 10 11 import javax.sound.sampled.AudioFormat; 12 import javax.sound.sampled.AudioInputStream; 13 import javax.sound.sampled.AudioSystem; 14 import javax.sound.sampled.Clip; 15 import javax.sound.sampled.DataLine; 16 import javax.swing.ImageIcon; 17 import javax.swing.JOptionPane; 18 import javax.swing.JPanel; 19 import javax.swing.SwingUtilities; 20 21 22
public class MainPanel extends JPanel implements MouseListener { 23
24
private int animalType = 0; // 動物の種類 25
private Animal clickedAnimal = null; // クリックされた動物 26
private List<ImageIcon> images; // 動物の画像リスト 27
private File[] audioFiles; // 音声ファイル 28
private List<Animal> animals; // 動物のリスト 29
30
private int imgWidth = 100; // 画像幅 31
private int imgHeight = 100; // 画像高さ 32
33
private int x,y; // クリックされた座標の一時保管用フィールド 34 35 /** 36 * コンストラクタ 37 */ 38 public MainPanel() { 39 super(); 40 // マウスイベントを受け取れるようにする 41 addMouseListener(this); 42 // 初期化 43 /* List は直接 new できず、リストの種類を指定する必要がある。 44
* 普通に使う List は ArrayList で new すれば問題ない。*/ 45
images = new ArrayList<ImageIcon>(); 46
animals = new ArrayList<Animal>(); 47 } 48 49 /** 50 * ファイル数に応じて各インスタンスを初期化 51 * new したあと必ず呼ぶ 52 * @throws MyException 53 * Exception を発生させる可能性のあるメソッドには、throws 節を付け加える 54 */ 55
public void init() throws MyException { 56 // img ディレクトリを取得 57 /* File クラスはディレクトリを含むファイルの概念を表す 58 * 相対パスで書くことができる */ 59
File imgDir = new File("img"); 60
MainPanel.java
-5-
// img ディレクトリにあるファイルを配列にして全て取り出す 61
File imgFiles[] = imgDir.listFiles(); 62
// List に画像オブジェクトを追加 63
/* getAbsolutePath 関数:ファイルの絶対パスを String で返す*/ 64
for (int i=0; i<imgFiles.length; i++) { 65 images.add(new ImageIcon(imgFiles[i].getAbsolutePath())); 66 } 67 // サウンドファイルを sounds ディレクトリから取り出す 68
audioFiles = (new File("sounds")).listFiles(); 69 // 画像ファイルとサウンドファイルの数が合わなかったら Exception を発生させる 70 if (imgFiles.length != audioFiles.length) 71 // MyException オブジェクトを新規生成して throw すると、例外発生となる 72
throw new MyException("音声ファイルの数が合いません"); 73 } 74 75 /** 76 * 描画メソッド<br> 77 * repaint 関数から呼ばれる 78 */ 79 @Override 80
public void paintComponent(Graphics g) { 81 /* パネルにボタンなどが配置されているときのため 82 * 今回は実際に意味はないが、慣例として忘れないよう書いておく*/ 83 super.paintComponents(g); 84 // より様々な描画方法が可能になるようにキャスト 85 Graphics2D g2d = (Graphics2D)g; 86 // システムカラー(背景色)を設定 87 g2d.setColor(SystemColor.control); 88 // 画面をいったんクリア 89
g2d.fillRect(0, 0, this.getWidth(), this.getHeight()); 90
// 動物描画 91
/* Java5 からは可変長配列 List のループを以下ように書くことができる 92
* animal には animals リストから順にとった Animal オブジェクトがはいる */ 93
for (Animal animal : animals) { 94 // 画像を描画 95 /* drawImage(画像オブジェクト, x 座標, y 座標, 幅, 高さ, ImageObserver) 96 * ImageObserver は画像のロードを通知するもの。たいていは this でよい */ 97 g2d.drawImage(images.get(animal.getAnimalType()).getImage(), 98 animal.getCenterPoint().x-animal.getSize().width/2, 99 animal.getCenterPoint().y-animal.getSize().height/2, 100
animal.getSize().width, animal.getSize().height, this); 101 } 102 } 103 104 105 /** 106 * マウスクリックで呼ばれる関数 107 */ 108 @Override 109
public void mouseClicked(MouseEvent e) { 110 // クリックされた座標を取得 111 x = e.getX(); 112 y = e.getY(); 113
int onImageIndex = 0; // 画像上クリックなら index(動物の種類),そうでなければ ListSize 114
/* animals の中の Animal オブジェクトを順に見て、クリックされた場所が 115
* 動物画像の中に含まれるかどうかをみていく*/ 116
for (Animal animal : animals) { 117 // 動物画像の中でクリックされていたらループから抜ける 118 if (animal.contains(x, y)) 119 break; 120
MainPanel.java -6- onImageIndex ++; 121 } 122 // 動物画像の中でクリックされていたら鳴き声を再生 123 if (onImageIndex < animals.size()) { 124 try { 125 // クリックされた動物を取得 126 clickedAnimal = animals.get(onImageIndex); 127 // 動物の種類に応じた鳴き声を再生 128 play(clickedAnimal.getAnimalType()); 129
} catch (MyException ex) { 130 // エラーをダイアログ表示 131 // JOptionPane.showMessageDialog(フレーム,メッセージ,タイトル,アイコンの種類) 132 JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(this), 133 ex.getMessage(), "再生エラー発生", JOptionPane.ERROR_MESSAGE); // 上と合わせて 1 行 134 } 135 } 136 // 動物画像の外でクリックされていたら画像を表示 137 else { 138 // Animal オブジェクトを生成 139
Animal animal = new Animal(animalType, imgWidth, imgHeight); 140 // 中心座標を設定 141 animal.setCenterPoint(x, y); 142 // リストに追加 143 animals.add(animal); 144 // 再描画 145 repaint(); 146 } 147 } 148 149 /** 150 * 音声再生メソッド 151 * @param index 152 * @throws Exception 153 */ 154
private void play(int index) throws MyException { 155
try { 156
// オーディオ入力ストリームを取得 157
AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFiles[index]); 158
// オーディオ形式を取得 159
// AU、AIFF、WAVE 形式に対応している 160
AudioFormat format = audioStream.getFormat(); 161
// データラインの情報(フォーマットなど)を作成 162
DataLine.Info di = new DataLine.Info(Clip.class, format); 163
// 情報に基づいてラインを取得 164
// Clip はデータをメモリ上に読み込んでおいてから再生する 165
Clip clip = (Clip) AudioSystem.getLine(di); 166 // ラインを開く 167 clip.open(audioStream); 168 // ラインでのデータ入出力を可能にする 169 clip.start(); 170 // ラインからキューに入っているデータを排出 171 clip.drain(); 172 } catch (Exception e) { 173
throw new MyException("再生失敗:"+e.getMessage(), e); 174 } 175 } 176 177 /* MouseListener を implements しているため、 178 * mouseClicked・mouseEntered・mouseExited・mousePressed・mouseReleased の 179 * 4つとも記述しなければならないが、このサンプルで使うのは 180
MainPanel.java -7- * mouseClicked だけなので後は空でよい。 */ 181 182 @Override 183
public void mouseEntered(MouseEvent e) { 184 } 185 186 @Override 187
public void mouseExited(MouseEvent e) { 188 } 189 190 @Override 191
public void mousePressed(MouseEvent e) { 192 } 193 194 @Override 195
public void mouseReleased(MouseEvent e) { 196 } 197 198 199 /** 200 * 動物の種類 setter 201 * @param aimalType 202 */ 203
public void setAnimalType(int animalType) { 204 this.animalType = animalType; 205 } 206 } 207 AnimalsFrame.java ・・・(中略)・・・
mainPanel = new MainPanel(); // 例外処理を記述する
try {
mainPanel.init(); } catch (MyException e) {
// メッセージダイアログを表示する
JOptionPane.showMessageDialog(this, e.getMessage(), "エラー", JOptionPane.ERROR_MESSAGE); // プログラム強制終了
System.exit(-1); }
getContentPane().add(mainPanel, BorderLayout.CENTER); ・・・(中略)・・・