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