広告

■□■□■□■□■□■□■□■□■□■□■□■□■□■□■
                      2012年10月08日

   Java総合講座 - 初心者から達人へのパスポート
                 2009年11月開講コース 064号

                                セルゲイ・ランダウ
 バックナンバー: http://www.flsi.co.jp/Java_text/
■□■□■□■□■□■□■□■□■□■□■□■□■□■□■


-------------------------------------------------------
・現在、このメールマガジンは以下の2部構成になっています。
[1] 当初からのコース:vol.xxx(xxxは番号)が振られています。
   これは現在、中級レベルになっています。
[2] 2009年11月開講コース:xxx号(xxxは番号)が振られています。
   これは現在、初心者向けのレベルになっています。
・このメールマガジンは、画面を最大化して見てください。
小さな画面で見ていると、不適切な位置で行が切れてしまう
など、問題を起すことがあります。
・このメールマガジンに掲載されているソース・コード及び
文章は特に断らない限り、すべて筆者が著作権を所有してい
ます。また、これらのソース・コードは学習用のためだけに
提供しているものです。
-------------------------------------------------------


========================================================
◆ 01.グラフィックスのプログラミング
========================================================


今回は、時計に目覚まし(アラーム)の機能をつけましょう。

普通の目覚まし時計では、目覚ましの機能を有効にするためには、
(1) アラームを鳴らしたい時刻を設定する。
(2) アラーム機能をオンにする。
という2つの操作を行います。

逆にアラームが鳴っているときにそれを止めるためには、
(3) アラーム機能をオフにする。
という操作を行います。

今回のプログラムでは、(1)の操作のためにアラームの時刻を
JComboBoxを使って数値で設定する機能を追加し、(2)と(3)のため
にJToggleButtonを使ってアラーム機能をオン/オフに設定する
機能を追加することにします。
(ただし、JToggleButtonはオン/オフがちょっとわかりにくいの
で、わかりやすくしたい人は、代わりにJCheckBoxなどを使用して
みてください。JCheckBoxの使用は演習にします。)
そして、設定された時刻が来るまで監視し、時刻が来たらアラーム音
を鳴らすための処理を別のスレッドで実行するようにします。

このプログラムでは、アラーム音の音声ファイルが必要になりますが、
アラーム音のファイルは下記のホームページの064号の項に掲載し
てありますので、ダウンロードしてください。

http://www.flsi.co.jp/Java_text/

アラーム音のファイル名はalarm01.auです。
ダウンロードしましたら、このファイルをJavaWorksフォルダーの中
のJStudy1フォルダー配下のbinフォルダーの中にコピーしてください。

┌補足─────────────────────────┐
この.auという拡張子がついているファイルは、Sun audio file
と呼ばれる(auはaudioの略)音声ファイルの形式です。圧縮さ
れた音声ファイルなので、サイズがかなり小さくて済み、インター
ネットなどでダウンロードして利用するのには都合がいい形式で
すが、その代わりに音質が悪いという欠点があります。
└───────────────────────────┘


では、さっそくEclipseを起動して、作業を始めましょう。

jp.co.flsi.lecture.clockパッケージの中にアラーム関連の処理
を行うためのAlarmJPanelというクラスをJPanelのサブクラスとし
て作成しましょう。

(1) パッケージ・エクスプローラーの中のJStudy1のsrc配下の
jp.co.flsi.lecture.clock
を右クリックし、「新規」→「その他」を選択します。

(2) 「新規」ウインドウにおい「WindowBuilder」配下の
「Swing Designer」配下の「JPanel」を選択し、「次へ」ボタンを
クリックします。

(3)  「ソース・フォルダー」に「JStudy1/src」が入力されていること
を確認し、「パッケージ」がjp.co.flsi.lecture.clockになっていること
を確認し、「名前」の欄に

AlarmJPanel

と入力しましょう。

(4) 「スーパークラス」が「javax.swing.JPanel」になっていることを確認し、
「完了」ボタンをクリックします。


AlarmJPanelのエディターが開きましたら、class文に「implements Runnable」
を追加しておきましょう。つまり、ソース・コードを
--------------------------------------------------------
package jp.co.flsi.lecture.clock;

import javax.swing.JPanel;

public class AlarmJPanel extends JPanel implements Runnable {

   /**
    * Create the panel.
    */
   public AlarmJPanel() {

   }

}
--------------------------------------------------------
というふうに編集します。

そうすると、AlarmJPanelに赤い下線が表示されますね。これは
インターフェースRunnableのメソッドが実装されていないから
(コンパイル)エラーになるためです。

そこで、AlarmJPanelの部分にカーソルを入れてCtrl+1する(Ctrlキーを押し
ながら、数字の1キーを押す)と表示されるメニューの中から「実装されていない
メソッドの追加」を選択して下さい。
(ついでながら、「Eclipseでエラーや警告に対処するためのメニューを表示する
には該当箇所にカーソルを入れてCtrl+1」と覚えておいて下さい。059号を参照の
こと。)

そうすると、ソース・コードが
--------------------------------------------------------
package jp.co.flsi.lecture.clock;

import javax.swing.JPanel;

public class AlarmJPanel extends JPanel implements Runnable {

   /**
    * Create the panel.
    */
   public AlarmJPanel() {

   }

   @Override
   public void run() {
      // TODO 自動生成されたメソッド・スタブ

   }

}
--------------------------------------------------------
というふうに、自動的にrun()メソッドが追加されますね。

┌補足─────────────────────────┐
ちなみにコメント行に「TODO」と書かれているのは、あとで編集
すべきことを意味します。ここでは、自動生成されたメソッドに
対して「TODO」が自動的に書かれていますが、編集を後回しに
しておきたい(やり残しの作業がある)行などに対して自分で

// TODO ・・・(何をすべきかの説明文)・・・

といった形式で「TODO」を書いておけば、目印になります。
└───────────────────────────┘


続いて、Designビューを開き、このパネル(JPanel)を適切な
サイズにしておきましょう。
JPanelの部分を選択(画面の中の灰色の部分をクリックするか、
または、Components欄の(javax.swing.JPanel)という文字列を
クリックすると選択できる)し、Properties欄の
「Show advanced properties」ボタン(マウス・ポインターをのせる
と「Show advanced properties」と表示されるボタン)をクリックし、
sizeプロパティーの値を
130,70
に変更して下さい。(sizeプロパティーの右端の「・・・」ボタンを
クリックし、「サイズ」ウインドウで「幅」欄、「高さ」欄に
それぞれ、130と70を入力して「OK」ボタンをクリックします。)

なお、このパネルはサイズが小さいですから、あとでGUI部品を
貼り付けるときには、きれいに収まるように各GUI部品を小さめ
に調整してください。

続いて、このパネルのLayoutManagerをnullにしておきましょう。
すなわちJPanelの画像を右クリックして「Set Layout」→
「Absolute layout」を選択します。

また、このパネルの背景(background)を白色にしておきましょう。
パネルの画像の中をクリックして選択状態にし、Properties欄の
のbackgroundプロパティーの値をColor.WHITE(backgroundプロパ
ティーの右端の「・・・」ボタンをクリックし、「Color chooser」
ウインドウの「AWT colors」タブのページでWHITEを選択し、
「OK」ボタンをクリック)にしておきます。

┌補足─────────────────────────┐
パネルが白色だと、パネルが選択状態でないときには背景の白色と
区別がつかなくなって、パネルがどこにあるのか分からなくなって
しまいますが、そういうときはComponents欄の(javax.swing.JPanel)
を選択してやればパネルが選択状態になって分かります。)
└───────────────────────────┘


では、このパネルに、以下のようにGUI部品を貼り付けていきましょう。

(1) アラームの時刻設定の説明書き用にJLabelを貼り付けましょう。
パネルの上端近くに貼り付けて下さい。
そのtextプロパティーを「アラームの時刻:」にしておきましょう。
文字列がきちんと表示されるように、サイズを適当に調整しておいて
ください。

(2) その下に、JComboBoxを貼り付けましょう。これは、アラームの時刻
のうち時(hour)を設定するためのものです。
変数名は
comBoxAlarmHH
にしておきましょう。
サイズを適当に調整しておいてください。

(3) その右隣にJLabelを貼り付けましょう。
そのtextプロパティーを「時」にしておきましょう。
サイズを適当に調整しておいてください。

(4) その右隣にJComboBoxを貼り付けましょう。これは、アラームの時刻
のうち分(minute)を設定するためのものです。
変数名は
comBoxAlarmMM
にしておきましょう。
サイズを適当に調整しておいてください。

(5) その右隣にJLabelを貼り付けましょう。
そのtextプロパティーを「分」にしておきましょう。
サイズを適当に調整しておいてください。

(6) パネルの下端近くにJToggleButtonを貼り付けましょう。
パネルが小さくて貼り付けが難しいので注意して下さい。
「10 x 49」などのように「数字 x 数字」が表示されている位置に貼りつける
必要があります。「数字 x 数字」が表示されない位置ではパネルからはみ出て
しまい、正しく機能しません。
貼りつけたあと、textプロパティーの値は無し(デフォルトの文字列はすべて
削除して空文字にする)にして、サイズ(幅)を調整して(幅を縮めて)、
位置を右端のほうにずらしておいてください。
変数名は
toggleButtonAlarmOnOff
にしておきましょう。

(7) その左隣にJLabelを貼り付けましょう。
そのtextプロパティーを「アラーム:」にしておきましょう。
サイズを適当に調整しておいてください。


続いて、comBoxAlarmHHとcomBoxAlarmMMの2つのJComboBoxに対して、
表示する値を以下のようにして設定しましょう。

まずcomBoxAlarmHHのほうですが、自動生成されたコードは
--------------------------------------------------------
      JComboBox comBoxAlarmHH = new JComboBox();
      comBoxAlarmHH.setBounds(0, 23, 46, 19);
      add(comBoxAlarmHH);
--------------------------------------------------------
というふうになっていますね。(ただし、数値は設定した位置・サイズ
によって異なります。)
これを次のように編集しましょう。
--------------------------------------------------------
      JComboBox comBoxAlarmHH = new JComboBox();
      comBoxAlarmHH.setBounds(0, 23, 46, 19);
      for (int i = 0; i < 24; i++) {
         comBoxAlarmHH.addItem(Integer.toString(i));
      }
      add(comBoxAlarmHH);
--------------------------------------------------------
何を編集したのかわかりますね。これでcomBoxAlarmHHには0時から23時
までの時刻が選択できるようになります。

続いてcomBoxAlarmMMのほうですが、自動生成されたコードは
--------------------------------------------------------
      JComboBox comBoxAlarmMM = new JComboBox();
      comBoxAlarmMM.setBounds(68, 23, 46, 19);
      add(comBoxAlarmMM);
--------------------------------------------------------
というふうになっていますね。(ただし、数値は設定した位置・サイズ
によって異なります。)
こちらも同様に次のように編集しましょう。
--------------------------------------------------------
      JComboBox comBoxAlarmMM = new JComboBox();
      comBoxAlarmMM.setBounds(68, 23, 46, 19);
      for (int i = 0; i < 60; i++) {
         comBoxAlarmMM.addItem(Integer.toString(i));
      }
      add(comBoxAlarmMM);
--------------------------------------------------------
これでcomBoxAlarmMMには0分から59分までの時刻が選択できるように
なります。

実際に動作を確認するには、パッケージ・エクスプローラーからAlarmJPanel.java
を右クリックし、「実行」→「Java Bean」を選択します。
このとき、JLabelの文字が表示しきれていない(端が欠けてしまっている等)など
貼りつけたGUI部品の位置やサイズが不適切であることが発覚した場合は、Designビュー
に戻ってGUI部品の位置やサイズを調整し直してください。
Designビューでの見え方と、実際にアプリケーションを実行したときの見え方には
多少違いがありますので、このような調整が必要になります。


なお、comBoxAlarmMMやcomBoxAlarmMMは、のちに外部からアクセスする(つまり、
外部から目覚しを鳴らす時刻を設定する)可能性がありますので、外部からアクセス
できるように設定しておきましょう。そのためには、Designビューにおいて、
これらのコンボボックス(comBoxAlarmMMとcomBoxAlarmMM)をそれぞれ、右クリック
し、「Expose component...」を選択します。そして「Expose component」ウインドウ
が開いたら、「OK」ボタンをクリックします。(comBoxAlarmMMとcomBoxAlarmMMの
それぞれに対して同じ操作を行います。)
そうすると、comBoxAlarmMMとcomBoxAlarmMMが(元々はローカル変数だったものが)
それぞれ自動的にフィールドに変更され、かつ、自動的にgetter(getメソッド)が
生成されます。



では次に、設定された時刻になったらアラーム音を鳴らすためのコード
を書きましょう。
「1分ごとに時刻をチェックして、現在時刻が設定された時刻と等しければ
アラーム音を鳴らす」という処理をループで実行します。
(目覚まし機能はそんなに正確である必要はありません(目覚しが鳴っても
もう少し寝たいというのが人情で、普通の人はそれより遅れて起床する??)
から、1分ごとのチェックで充分だと考えます。)

前回お話したように、このようなループの処理は別のスレッドで行う
必要がありますから、run()メソッドに記述します。

その前に、アラーム機能がオンになっているかオフになっているかを
示すフィールドとして、下記のようなフィールドを追加しておいて
ください。
--------------------------------------------------------
private boolean alarmMode = false;
--------------------------------------------------------

また、アラーム音のオブジェクトを入れるフィールドとして下記の
ようなフィールドを追加しておいてください。
--------------------------------------------------------
private AudioClip audioClip = null;
--------------------------------------------------------
(AudioClipはjava.appletパッケージにはいっています。)

さらに、このフィールドにアラーム音のオブジェクトをセットしたり、
逆に取り出したりするために次のようなsetter(setメソッド)、
getter(getメソッド)を追加しておきましょう
--------------------------------------------------------
public void setAudioClip(AudioClip audioClip) {
   this.audioClip = audioClip;
}

public AudioClip getAudioClip() {
   return audioClip;
}
--------------------------------------------------------

また、現在の時刻がアラームの設定時刻と等しいかどうかをチェック
するための下記のようなメソッドも追加しておきましょう。
--------------------------------------------------------
private boolean isAlarmTime() {
   GregorianCalendar newTime = new GregorianCalendar();
   int alarmHH, alarmMM;
   try {
      alarmHH = Integer.parseInt((String)(getComBoxAlarmHH().getSelectedItem()));
      alarmMM = Integer.parseInt((String)(getComBoxAlarmMM().getSelectedItem()));
   }
   catch (NumberFormatException e) {
      return false;
   }
   if (newTime.get(Calendar.HOUR_OF_DAY) == alarmHH
         && newTime.get(Calendar.MINUTE) == alarmMM) {
      return true;
   }
   return false;
}
--------------------------------------------------------



では、run()メソッドのプログラミングをしましょう。
ソース・コード上の下記の部分
--------------------------------------------------------
   @Override
   public void run() {
      // TODO 自動生成されたメソッド・スタブ

   }
--------------------------------------------------------
を次のように編集しましょう。
--------------------------------------------------------
   @Override
   public void run() {
      if (audioClip == null) return;
      while (alarmMode) {
         if (isAlarmTime()) {
            while (alarmMode) {
               getAudioClip().play();
               try {
                  Thread.sleep(1000);
               }
               catch (InterruptedException e) {
               }
            }
         }
         try {
            Thread.sleep(60000);
         }
         catch (InterruptedException e) {
         }
      }
   }
--------------------------------------------------------


続いて、このスレッドを起動するための下記のようなメソッドを
追加しましょう。
--------------------------------------------------------
public void alarmThreadStart() {
   alarmMode = true;
   Thread aThread = new Thread(this);
   aThread.start();
}
--------------------------------------------------------

また、このスレッドを停止するための下記のようなメソッドを追加
しましょう。

--------------------------------------------------------
public void alarmThreadStop() {
   alarmMode = false;
}
--------------------------------------------------------


最後に、toggleButtonAlarmOnOffのトグル・ボタンがオンにされた
ときにalarmThreadStart()メソッドを呼び出し。オフにされたときに
alarmThreadStop()が呼び出されるようにプログラミングしましょう。
Designビューでトグル・ボタン(toggleButtonAlarmOnOff)を右クリッ
クし、「Add event handler」→「アクション」→「actionPerformed」
を選択します。

下記のコードが自動生成されていますから、
--------------------------------------------------------
      toggleButtonAlarmOnOff.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
         }
      });
--------------------------------------------------------
これを下記のように編集しましょう。
--------------------------------------------------------
      toggleButtonAlarmOnOff.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            if (toggleButtonAlarmOnOff.isSelected()) alarmThreadStart();
            else alarmThreadStop();
         }
      });
--------------------------------------------------------

すると、例によってtoggleButtonAlarmOnOff変数がfinal指定されていない
ことに対してエラー・メッセージが出ます(toggleButtonAlarmOnOffに赤色
の下線が引かれるので、そこにマウス・ポインターを持って行くとメッセージ
が表示される)ので、toggleButtonAlarmOnOff変数をfinal指定にしましょう。
--------------------------------------------------------
JToggleButton toggleButtonAlarmOnOff = new JToggleButton("");
--------------------------------------------------------
という行にfinalを指定して
--------------------------------------------------------
final JToggleButton toggleButtonAlarmOnOff = new JToggleButton("");
--------------------------------------------------------
というふうに編集して下さい。


以上で、AlarmJPanelは完成です。



次に、このAlarmJPanelをClockAppletに貼り付ける作業に移ります。
ClockAppletのソース・コードを開きましょう。

まず、AlarmJPanelのオブジェクトを入れるフィールドとして下記の行を
ソース・コードに追加して下さい。
--------------------------------------------------------
private AlarmJPanel alarmJPanel;
--------------------------------------------------------

続いて、ClockApplet()コンストラクターの最後に下記のようなコードを
追加しましょう。
--------------------------------------------------------
      alarmJPanel = new AlarmJPanel();
      alarmJPanel.setBounds(170, 0, 130, 70);
      getContentPane().add(alarmJPanel);
--------------------------------------------------------


では、続いてClockAppletのinit()メソッド
--------------------------------------------------------
   public void init() {
      this.setSize(300, 200);
      this.setContentPane(getContentPane());
      clockJPanel.clockStart();
   }
--------------------------------------------------------
を編集して、次のようにアラーム音のファイルを取り込んで
AlarmJPanelに渡すコードを追加しましょう。
--------------------------------------------------------
   public void init() {
      this.setSize(300, 200);
      this.setContentPane(getContentPane());
      clockJPanel.clockStart();
      AudioClip audioClip = getAudioClip(getDocumentBase(), "alarm01.au");
      alarmJPanel.setAudioClip(audioClip);
   }
--------------------------------------------------------

getAudioClip()メソッドはAppletのメソッドで、指定された場所
(ここではgetDocumentBase()メソッドを呼び出すことによって、
アプレットが置かれているHTMLの場所と同じ場所を指定している)
から指定されたファイル名(ここではalarm01.au)の音声ファイル
を取り出して、AudioClip型のオブジェクトにしてくれます。
そこで、そのAudioClipオブジェクトをAlarmJPanelのsetAudioClip()
メソッドを呼び出すことによって、AlarmJPanelに渡しています。



以上で、アラームの機能は完成です。
ClockAppletを起動してテストしてみてください。

アラームの時刻をセットしてアラームをオンにすれば、ちゃんとセット
した時刻にアラーム音が鳴りますね。(ただし、1分おきにチェックして
いるので、タイミングが悪ければ最大1分ほどアラームが遅れることが
あります。)
また、アラーム音が鳴っているときにアラームをオフにすれば、ちゃん
と音が止まりますね。



では、今回はここまでにします。なお、今回作成したアプレットはホー
ムページにも掲載しておきますので、完成したアプレットの動きを確認
したい人は下記ホームページの064号の項目から実行してみてください。

http://www.flsi.co.jp/Java_text/

何か、わからないところがありましたら、下記のWebページまで質問を
お寄せください。


(続く)




========================================================
◆ 02.文法解説 [アプレット(5)]
========================================================

[アプレット(5)「アプレットの情報」]

AppletのgetAppletInfo()メソッドを実装(オーバーライド)する
ことにより、アプレットビューアでアプレットを起動したときに
アプレットの情報を表示させることができます。

たとえば、アプレットのソース・コードの中に
--------------------------------------------------------
public String getAppletInfo() {
   return "Title: ClockApplet \n"
      + "Author: Sergei Landau, 2007 \n"
      + "A sample alarm clock.";
}
--------------------------------------------------------
というようにgetAppletInfo()メソッドをコーディングしておくと、
このreturn文で返す内容が、アプレットビューアの「アプレット」
メニューの中の「情報」というメニュー項目を選択することによっ
て表示されます。

このとき同時にパラメーターの情報も表示されます。これは、Applet
のgetParameterInfo()メソッドを実装(オーバーライド)することに
より表示されます。
たとえば057号の「アプレットのパラメーター」のサンプルに合わせ
た情報にすると、
--------------------------------------------------------
public String[][] getParameterInfo() {
   String[][] info = {
      {"rectwidth", "positive integer",
       "The width of the rectangular. Default is 100."},
      {"rectheight", "positive integer",
       "The height of the rectangular. Default is 50."}
   };
   return info;
}
--------------------------------------------------------
というようなコードを書いておけばいいのです。
それぞれ、パラメーター名、型の種類、説明、という3種類の情報を
パラメーターごとに書いておきます。

これらの情報を提供するコードは、アプレットの一般ユーザーには
役に立ちませんが、開発者にとっては覚書として利用することがで
きます。


(続く)



以上、今回は
┌───────────────────────────┐
・アプレットでの音声ファイルの取り込み(getAudioClip()メソッドの使用)方法
・音声ファイルからの音の鳴らし方(AudioClipのplay()メソッド)
・指定された時刻に処理を実行するためのプログラミング
・アプレット情報のコーディング方法
└───────────────────────────┘
を学習しました。
では、また来週。


(続く)



================================================
◆ 03.演習問題
================================================

アラーム機能のオン/オフの設定に使ったGUI部品がJToggleButtonでは
ちょっとわかりにくいので、JToggleButtonの代わりにJCheckBoxを使用
してプログラムを修正してみてください。
やり方がわからない人は、下記Webページにて質問をお寄せください。



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      http://www.flsi.co.jp/Java_text/
★このメールマガジンは
     「まぐまぐ(http://www.mag2.com)」
 を利用して発行しています。
★バックナンバーは
      http://www.flsi.co.jp/Java_text/
 にあります。
★このメールマガジンの登録/解除は下記Webページでできます。
      http://www.mag2.com/m/0000193915.html
★このメールマガジンへの質問は下記Webページにて受け付けて
 います。わからない所がありましたら、どしどしと質問をお寄
 せください。
      http://www.flsi.co.jp/Java_text/
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Copyright (C) 2012 Future Lifestyle Inc. 不許無断複製