最終更新日 |
[関連]
Java入門1 Java入門2 Java入門3ーアプレット Java応用1ーSwing、GUI
Javaのプログラミング2ーApplet,Swing(学生向けにまとめたページ)。
[このページの内容]
6 スライドショー 7 スライドショーのパッケージ化 8 スライドショー途中経過、失敗から成功へ
[Java応用1ーSwing、GUIーの内容]
1 Swingの基本ーイベント処理 2 ボタンによる背景色の切り換え
3 Midiファイルの選択と演奏ーコンボボックス 4 御神籤ーイメージ処理 5 JARファイルの作成方法
Java入門3でアプレット 、ホームページ上でグラフィックスなどを動かすことのできる、Javaのプログラムやスレッドによる動きのある例を、そして、Java応用1ではSwing によるGUI(Graphic User Interface)の例を紹介してきた。
この応用2はその延長上、総合的な例としてスライドショーの例を紹介する。
「Java入門1」の1-4-1で紹介した JavaTM 2 Platform Standard Edition 5.0API 仕様 は、引き続き必要。
[ブラウザソフトのJava対応]
アプレットを見るには、ブラウザソフトがJavaに対応していないといけない(JavaのVM(仮想マシン)をサポート)。マイクロソフトのIEは、Java1.1という古いシステムをサポートしていたが、XPのSP1以降、サポートをうちきった。その後は、各メーカが独自に対応しているが、統一はされていない。もし、このページのアプレット画面が見られない場合は、ブラウザソフトのJava対応 を参照されたい。
複数の画像に同じ名前で連続した番号をつけたファイル名としておき、その番号をスレッドで休止中に増やすという操作である。やはり、JavaScriptでやった例がある。JavaScriptの応用1-3章
そこでは、mp3で圧縮した音楽もいれてやっているが、Java応用1の3章 で使ったJavaのAudioClipインターフェイスではmp3はだめだったので、midiとした。音楽が入るとstopボタンはぜひ必要となり、さらに写真説明も入れたいとなって、GUI、スレッド、画像処理 と、結構総合的なプログラム例になった。特にアプレットでは制約が強く、大変難航した末、1週間もかかって、ようやくできた(Slideshow.java)。
start,stopボタンも写真説明もない単純なもの(Slideshow4.java)は簡単にできたが、start,stopボタンをつけると、写真表示のコードはJPanelを拡張したクラスに書く必要があり、矛盾する要素がからみあって難航、針の穴を通すような感じがした。途中経過の一部と失敗の過程をプログラムのありかとコメントをつけて、8章で詳述する。
1 [Slideshowプログラム] import java.applet.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.net.*; /* <applet code="Slideshow.class" width=700 height=600></applet> */ public class Slideshow extends JApplet implements ActionListener, Runnable { SlidePanel slidepanel; JButton startButton; JButton stopButton; AudioClip onceClip; ImageIcon[] images; Thread t; int i = 0; int height; int n = 7; //NUM_IMAGES String[] str={"コスモス(昭和記念公園 2003)","コスモス1","コスモス2", "コスモス3","コスモス4","コスモス5","コスモス6"}; String slideName = "kosmos"; String midiFile= "coroptica.mid"; public void init(){ Container contentPane = getContentPane(); slidepanel = new SlidePanel(); Dimension d = getSize(); height = d.height; JPanel minipanel= new JPanel(); startButton = new JButton("Start"); stopButton = new JButton("Stop"); startButton.addActionListener(this); stopButton.addActionListener(this); contentPane.add(minipanel,BorderLayout.NORTH); contentPane.add(slidepanel,BorderLayout.CENTER); minipanel.add(startButton); minipanel.add(stopButton); minipanel.setBackground(Color.green); slidepanel.setBackground(Color.yellow); images = new ImageIcon[n]; for (int j = 0; j < n; j++) { String imageName = slideName + j + ".jpg"; try{images[j]=new ImageIcon(new URL(getDocumentBase(),imageName)); } catch (Exception e) {} } } public void actionPerformed(ActionEvent event) { Object source = event.getSource(); if (source == startButton) { onceClip = getAudioClip(getCodeBase(),midiFile); onceClip.play(); //AudioPlay // スレッドを起動する t = new Thread(this); t.start(); } if (source == stopButton) { onceClip.stop(); //AudioStop stop(); } } public void run() { try { Thread mythread = Thread.currentThread(); while(t == mythread) { slidepanel.init(); Thread.sleep(3000); i++; if (i == n) i=0; } } catch (Exception e) { } } public void stop() { t=null; } class SlidePanel extends JPanel { public void init() { repaint(); } public void paintComponent(Graphics g) { super.paintComponent(g); // System.out.println("paint i = " + i + " str = " + str); images[i].paintIcon(this,g,50,30); // g.drawImage(icon.getImage(),50,30,null); g.setFont(new Font("Serif", Font.BOLD, 30)); g.setColor(Color.blue); g.drawString("" + str[i],220,height-50); } } } [実行結果] スライドショー ソースプログラム Slideshow.java [総括コメント] 1 スライドショーにはスレッド使用、音楽もつけたいと、GUIのstart,stopボタンをつける。そのため、 JPanelを拡張した別クラスを作る必要がでてきた。そこにイメージを表示するのだが、イメージオブジェクト の生成に、13項で後述する画像ファイル名をImageIconコンストラクタの引数 とする手法を使った。 appletviewer で見るとOKだが、ネットではだめとなるエラーになる(応用1の4-1 コメント7でもふれている)。 そのため、ことが難しくなり、約1週間かかり、2004/12/16深夜、ようやくできた。 その後、6章のパッケージ化ができたのが新年元旦夜、7章のJARファイルにまとめることができたのは、 1/8と、スライドショーに約1月かけたことになる)。 2 結局、class Slideshowというメインのクラスで、3項の手法を使って、スライド画像をすべて 一括ローディング して、imageオブジェクトの配列にする(「Javaチュートリアル」P484参照)。 それを別クラスに渡して表示させようとして失敗の連続。 結局、JPanelを拡張したクラスを内部クラス とすることで解決した。 (後に、別クラスにしても、必要な引数を全てクラス変数 とすることでも解決した)。 3 try{ images[j]=new ImageIcon(new URL(getDocumentBase(),imageName)); } catch (Exception e) {} であるが、画像ファイルのurlをImageIconコンストラクタの引数 にしているところは、 応用1 の4-1と同じ、コメント2,3,4に対応している。 なお、URLクラスのコンストラクタには、MalformedURLExceptionの例外処理が必要と、4-1に書いたが、 「core Java」2巻のP100には、その上位クラスにあたる、Exception eを使っていたので真似て簡単にした。 この処理をJPanelを拡張した別クラスの中に書くと、Appletクラスの拡張がないため、getDocumentBase() がエラーとなり、難航することになった(8章参照)。 4 APIでみて、URLクラスの引数が2つあるコンストラクタで該当するのは、 URL(URL context, String spec) 詳細説明には、前者が「context - 仕様を解析するコンテキスト」、 後者が「spec - URL として解析される」 とあるが、前者がgetDocumentBase()ないしgetCodeBase()、後者がimageNameに対応するとは超難解。 5 playボタンが押されることによって発生するイベントはactionPerformedメソッドで受け止めら れ、ここでgetAudioClipインターフェイスによるオブジェクトを生成して、midiを鳴らすととも に、スレッドを起動する。 6 runメソッドからSlidePanelクラスのinitメソッドを呼び出して、repaintメソッドからpaintComponent メソッドを呼び出す。ここで、imageオブジェクトの配列をもとに、最初の写真を表示する。 また、説明文も配列をもとに表示する。runメソッドに戻って3秒中断しては、スライド写真の番号iを 1増やして、4の動作を繰り返す。 7 数多く試行した中で、ネット上で動作するものとしては、ようやく成功した方法だったが、内部クラスにするこ とで、imageオブジェクトの配列やiなどの引数をどのような方法で渡すかを工夫する必要もなくなり、 コーディングする手間も省ける。 8 難航した理由のひとつに、画像を表示するpaintComponentメソッド がスレッドを起動するrunメソッド を経て呼ばれるとは限らないことである(6項をバスしてしまう)。したがって、paintComponentメソッド には、最初から画像が表示できるように準備しておかないといけないことがあった。 [細部のコメント] 9 写真画像のパネルは、JPanelを拡張したSlidePanelクラスのオブジェクトとして生成して、 そのサイズを600,480と指定する(写真のサイズ)。しかし、アプレットのサイズが優先して必要なか ったようだ。削除した。 slidepanel = new SlidePanel(); Dimension d =new Dimension(600,480); slidepanel.setPreferredSize(d); 10 start,stopボタンを写真画像のパネルslidepanelから独立したパネル上におくため、minipanel とした。 JPanel minipanel= new JPanel(); 背景を緑にしたminipanelを上に、背景を黄色にしたslidepanelを下に配置する。 contentPane.add(minipanel,BorderLayout.NORTH); contentPane.add(slidepanel,BorderLayout.CENTER); アプレットの大きさを適当にすると、写真に枠がついているように見える。 11 SlidePanelクラスで、images[i].paintIcon(this,g,50,30);と、x=50,y=30の位置から写真を 表示する。このpaintIconメソッドは「Javaチュートリアル」P484に一部紹介のある、Javaの マスコット、ペンギンのDuke君のアニメーションだが、ネット上にあるソースにあったものである。 ただし、よく使ってきた g.drawImage(images[i].getImage(),50,30,null);でも問題はない。 12 写真がたくさんあるので、image/slideshowディレクトリにまとめて、 String imageName = "../image/slideshow/slideName" + j + ".jpg"; とすると、ネットでは大丈夫だが、ローカルではだめなので、JARファイルにまとめることを前提 として、写真は同一フォルダにおく。 13 逆に、ローカルでは、images[j] = new ImageIcon(imageName); と簡単にできるところ、ネット ではだめ(java.security.AccessControlException: access deniedとなる)。 コメント3,4に書いたことが必要。 12 応用1 3章のコメント5で紹介したComboBoxDemo.javaの中に、下記があった。トライする価値がありそう。 picture.setIcon(new ImageIcon("images/" + petName + ".gif")); 13 失敗の連続だったが、その途中過程を残しておくのも必要と考えた。しかし、あまりに長くなるので、 8章にまわした。
スライドショーのプログラムをパッケージ化することで一般化して、写真と説明文、BGMを簡単に取り替えられるようにした。
二番目の孫の誕生からの140日間の成長を18枚の写真をまとめたのが、Mana.javaである。
そのディレクトリ構成は下記。
ボタンとスライド説明の画面は出るので、プログラムの流れには問題なさそうであったが、かんじんの写真が1枚も出ないため、スライドショーにならない。さんざん試行錯誤したあげく、一連の写真のjpgファイルとBGMのmidiファイルをhtmlファイルをおくことになる親ディレクトリ(Package) に移すことであっけなく解決した。ファイル整理の意味からも都合がよい。2004年暮れにはできなかったが、2005年元旦の夜にこの第二関門を通過できて完成。
Mana.javaは、Slideshowを拡張したサブクラスとし、Slideshowの諸変数(写真と説明文、BGMなど)に super.slideName="mana";のような形で代入するだけのいたって簡単なものである。
[アプレットのパッケージのディレクトリとファイル構成] PackageーーーーーーMana.html | ーーManaーーーーーMana.java | | | ーーMana.class | ーーSlideshowーーーSlideshow.java | ーーSlideshow.class [コンパイルと実行文] cd c:\HPBasic\Toppage-sample3\MySwing\Slideshow\/Package //カレントディレクトリは親ディレクトリに set CLASSPATH=Slideshow;Mana //コメント5追記参照 javac Mana\Mana.java appletviewer Mana.html //またはMana.htmlをダブルクリック
このスライドショーのプログラムをパッケージ化することで一般化して、写真と説明、BGMを簡単に取り替えられるようにした。まずは、順序として、5章のプログラムをそのままパッケージ化した例から(実は、多数の写真があるにもかかわらず、JARファイルにできないという問題点があるが、その解決策は7−2で)。
1 Mana.javaのプログラム //package Mana; 不要となった、コメント5追記参照 import slideshow.*; public class Mana extends Slideshow{ public void init() { String[] str={"初正月の羽子板(魔よけ?)","誕生、大きな泣き声(2004/8/9)","保育室でスヤスヤ(8/11)", "退院(8/17)", "家族で(2004/8/21)","美結ちゃんと(8/21)","初笑い?(4/8/23)","おとぼけ(8/26)", "ごきげん(9/4)","お風呂大好き(9/16)","しっかり(9/20)","メリーゴーラウンド(10/26)", "おすまし(11/2)","入院、小さなベッド(11/17)","ママと(12/9)","腹這い1(12/15)", "腹這い2(12/19)","ひいおばぁちゃんと(12/23)","お正月(2005/1/1)""親族の集まりで(1/2)"}; super.slideName="mana"; super.midiFile="hurusa_s.mid"; super.str=str; super.n=20; super.init(); } } 2 パッケージ化したslideshowのプログラム package slideshow; //packageとするという宣言 import java.applet.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.net.*; public class Slideshow extends JApplet implements ActionListener, Runnable { //サブクラスで与える変数は全てpublicとする、具体的な指定はサブクラスにまかせる。 public String slideName; //写真配列名 public String midiFile; //BGMのmidiファイル public String[] str; //写真説明文の配列 public int n ; //写真の総数 // 上記以外の変数宣言は6章に同じ、省略。 //init()メソッド以下も全て6章に同じ、省略 } } [実行結果] 真捺ちゃんの140日 Mana.java および Slideshow.java [コメント] 1 アプレットタグの中に書くcode属性をcode="Mana/Mana.class" とか codebase="Mana" とすると、 "java.lang.NoClassDefFoundError: Mana (wrong name: Mana/Mana)"という致命的なエラーとなって悩まされた。 2 1年以上も前に作った タートルグラフィックスとフラクタル で、アプレットのパッケージ化に成功している ので、それを参考にして、パッケージのためのディレクトリとファイルの区切りをスラッシュ"/"では なく、ドット"." にしてようやく第一関門を通過した。 3 つまり、<applet code="Mana.Mana.class" width=700 height=530> とする。 これで、一応ボタンとスライド説明の画面は出るようになったが、写真が出ない、その解決は7章冒頭 に書いた。あっけなく、拍子抜けするくらいであったが、基準、codebaseも親ディレトリ(Package) にな るということだろう。 4 package Manaは必要。これがないと、 java.lang.NoClassDefFoundError: Kosmos/Kosmos (wrong name: Kosmos) というエラーになる。 5 set CLASSPATH=. は必須(set CLASSPATH=c:\HPBasic\Toppage-sample3\MySwing2 とフルパスは必要はない)。 [2005/12 追記] Javaによる数学的例題 の 2-5 コメント4に書いたが、 set CLASSPATH=Slideshow;Manaとすることで、不可解だった4も不必要となった。ただし,次の7-2では、 やはり必要となった。依然として釈然としない。 また、package化したSlideshow.javaの保存先をslideshowと、小文字にすることにより、package slideshow; と小文字にできる。 6 コンパイルは javac Mana\Mana.java だけでよい。SlidesowディレクトリのSlidesow.javaも 同時にコンパイルされる。 7 最初、下記のように、Slideshowに引数つきのコンストラクタを作り、変数を引数渡しで考えたが、 失敗した(8-3-Aと共通しているか?)。 Slideshow sls = new Slideshow("mana",18,str); public Slideshow(String slideName, int n, String[] str) { this.slideName=slideName; this.n=n; this.str=str; System.out.println("constructor slideName = " + slideName + " str = " + str); } 8 そこで、superキーワード にした。 super.slideName="mana"; super.midiFile="hurusa_s.mid"; super.str=str; super.n=20; super.init();
多数の写真ファイルがあるし、Manaのクラスが1つ、Slideshowのクラスも2つある。JARファイル化したかったが、Imageオブジェクトの生成にImageIconを使っているので、Java応用1 の4-1同様、JARファイル化に失敗した。midiは鳴り、スライドの説明も変わるが、かんじんの写真が出ない。そこで、ImageIconの代わりに、Java応用1-2同様、Imageオブジェクトを使うことにした。
以下、変更部分だけを記述する。なお、JARファイルの作成のしかたなどはJava応用1の5 JARファイルの作成方法でまとめている。
1 Imageオブジェクトに変更したSlideshowのプログラム public class Slideshow extends JApplet implements ActionListener, Runnable { //下記以外同じ Image[] images; public void init(){ //下記以外同じ for (int j = 0; j < n; j++) { String imageName = slideName + j + ".jpg"; try { loadImage(new URL(getDocumentBase(),imageName),j); } catch (Exception e) {} } } public void loadImage(URL url,int j) throws InterruptedException { // thrown by MediaTracker.waitFor images[j] = getImage(url); MediaTracker tracker = new MediaTracker(this); tracker.addImage(images[j], 0); tracker.waitForID(0); /* int imageWidth = images[j].getWidth(null); int imageHeight = images[j].getHeight(null); resize(imageWidth, imageHeight);*/ } //以下全て同じ } } [コメント] 1 loadImageメソッドは 「CoreJava」2巻、P100にあるプログラムを参考にした(ほとんどそのまま)。 2 ImageIcon内部のloadImageメソッドは、MediaTrackerの処理をしてくれるようだが、Imageオブジェクト の場合は、この処理をいれないと、具合の悪いことが起こった(画像が出ないまま音とスライドの説明 が流れる)。全ての画像がロードされるまで待つ必要があった。 3 コメントにしたgetWidth,getHeightメソッドは、画像そのままの大きさをキャッチする。 いずれ、活用したい。
2 Tanigawa.javaプログラム
Mana.javaはまったく6-1と同じなので、ここでは、谷川、一の倉沢散策(Tanigawa.java)を紹介する。なお「秋の至仏に登る」も類似、コスモスはいままでの流れの中でテスト的にやったもの。
[2005/12 追記] ここでも、7-1のslideshowのパッケージはそのまま、取り込む。7-1のコメント追記に書いたのだが、ここでは、package Manaがないと、どうもうまくいかないことになった。
set CLASSPATH=slideshow;Mana; としたにもかかわらずである。packageについて完全に理解したとはいえないど残念なことになった。新たに、Mana2005も追加してみたが。
//cd c:\HPBasic\Toppage-sample3\MySwing\Slideshow\Jar //set CLASSPATH=. //javac Tanigawa\Tanigawa.java //jar cvf Tanigawa.jar Tanigawa/*.class slideshow/*.class *.jpg *.mid //appletviewer Tanigawa.html //jar xvf Tanigawa.jar (解凍) //jar tf Tanigawa.jar (解凍せずに内容一覧を表示) package Tanigawa; import slideshow.*; public class Tanigawa extends Slideshow{ public void init() { String[] str={"谷川、一の倉沢散策(2004/10/24)","土合スタート(11.35)","山水会御一行様","華のお二人", "マチガ沢(11.57)","魔の大岩壁(12.29)","日に映える紅葉との対比","一の倉沢案内板","谷川の紅葉", "照葉峡(15.09)","照葉峡の滝","澄みきった流れ"}; super.slideName="Tanigawa"; super.midiFile="itosi_s.mid"; super.str=str; super.n=12; super.init(); } } [スライドショー実行結果] 紅葉の谷川・照葉峡散策 秋の至仏に登る コスモス 真捺ちゃんの140日 真捺ちゃんの1年 美結ちゃんの1年8ケ月 [ソースプログラム] Tanigawa.java Shibutsu.java Kosmos.java Mana.java Mana2005.java Miyu.java 以上のいずれにも共通して使ったプログラム Slideshow.java [コメント] 1 jar cvf Tanigawa.jar Tanigawa/*.class slideshow/*.class *.jpg *.mid Tanigawa.html,Tanigawa.jarは親ディレクトリにおく。サブディレクトリ slideshowやTanigawaの中の classファイルのTanigawa.jarへの格納もこのような形でできる。 2 Tanigawa.javaのjar化は、最初、cvf Tanigawa.jar Tanigawa/*.class *.jpg *.mid とした。 slideshowをimportしているし、slideshowディレクトリにSlideshow.classがあればいいかと思った が、だめだった。jar cvf Tanigawa.jar Tanigawa/*.class slideshow/*.class *.jpg *.mid とした。 3 appletviewer Tanigawa.html 画像、スライド説明文は動くが、音が出ない。 appletviewer Tanigawa.Tanigawa.java 指定されたファイルが見つからないとのエラー。 appletタグは、Tanigawa.htmlの中のものとは異なる。下記のように変更したが、だめだった。 <applet code="Mana2005.class" archive="../../Mana2005.jar" width=700 height=570≶</applet≶ 結局、Tanigawa.htmlをダブルクリックするかアップしたもののみ動く。 JARのトライまとめ A 真捺ちゃんの140日 7-2 OK B コスモス・スライドショー 7-2 OK C 御神籤 「応用1」4-2 OK D 御神籤2 「応用2」4-1 写真がでない。 失敗したDとA,B,Cとの違い C URLコンストラクタ使用せず、パラメータ渡し。 A,B,C ImageIcon(URL url)というコンストラクタではなく、getImageメソッド使用。 ImageIconコンストラクタはjarファイルに対応していない? APIの知識不足orバグ? 下記は6-1のスライドショー。jarにまとめたTanigawa.jarをフルパスとしたarchive属性をもつ appletタグをここにはりつけると、エラーになる(ハードディスク上ではうまくいったのだが)。
6-1の冒頭にも書いたが、start,stopボタンも写真説明もない単純なもの(Slideshow4.java)は簡単にできたが、start,stopボタンをつけると、写真表示のコードはJPanelを拡張したクラスの中に書く必要があり、そのため難航した。すでに、6-1のコメントに書いたことも多いが、視点を変えて途中経過として残しておきたい。
8-1では失敗した例をいくつか出して、分かる範囲でその理由を述べるが、謎が残る。 8-2は、成功した6章と同じ例ながら、内部クラスとせず、JPanelを拡張したクラスのオブジェクト変数を生成する際、コンストラクタの引数で値を渡そうとして、ことごとく失敗。その試行錯誤の結果をしつこく書くが、謎が深まる。また、インスタンス変数やメソッドで受けとる方法も失敗。
8-3は、6章と同じく内部クラスとするだけで、8-1,8-2で失敗していたものが成功することを述べるが、その他では、Slideshowのクラス変数 で値を受けとる方法が成功。インスタンス変数ではだめだったので、クラス変数の効用を知った気になる。
1 Slideshow10.java [ソースプログラム] Slideshow10.java 1 String imageName = "kosmos" + i + ".jpg"; icon = new ImageIcon(imageName); ということで、写真表示ができるなら、さほど問題はなかったが、これは appletviewer Slideshow.java とか appletviewer Slideshow.htmlではいいが、ローカルなhtmlファイルを ブラウザで見るとかネットにアップするとだめ、2行目が 「java.security.AccessControlException: access denied」というエラーになる。 2 そこで、「入門4」の4-1のように、getCodeBaseメソッドを使って、画像ファイルのあるurlから ImageIconオブジェクトを生成することにした。 3 スレッド起動、runメソッドでスライド番号のiが決まる。ImageIconオブジェクトの生成はその後になる。 JPanelを拡張したクラス(SlidePanel)でgetCodeBaseメソッドを使ったところ、下記のエラーとなる。 C:\HPBasic\Toppage-sample3\MySwing\Slideshow100>javac Slideshow10.java Slideshow10.java:117: シンボルを解決できません。 場所 : SlidePanel10 の クラス URL baseURL = getCodeBase(); 2 Slideshow20.java [ソースプログラム] Slideshow20.java 4 Slideshow10.javaのエラー3は、getCodeBaseメソッドがApplet,JAppletを拡張したクラスの中でないと 使えないということだろう。そこで、getCodeBaseメソッドを使うコードをJAppletを拡張したクラス (Slideshow)の中に移す。 5 それで解決かと思いきや、問題はそう簡単ではなかった。あちこちにprint文を入れていて分かったのだが、 runメソッドでiが決まる。そこでImageIconオブジェクトを生成するupdateを呼んでいるのだが、それは無視 されて、JPanelを拡張したSlidePanelクラスのpaintComponentメソッドに飛び込んでしまう。 (ImageIconオブジェクトができていないから、NullPointerExceptionというエラー。 Slideshow20.javaの末尾に、print文を張り付けて、この動きを追っている。) 3 Slideshow30.java [ソースプログラム] Slideshow30.java 6 paintComponentは必要なときに自動的に呼ばれるものだが、不可解な動き。 ImageIconオブジェクトを生成するのがupdateでは弱いとみて、startメソッドにしてみた。 (startメソッドでスレッドを起動していたが、それをactionPerformedに移した)。 C:\HPBasic\Toppage-sample3\MySwing\Slideshow100>appletviewer Slideshow30.java Slideshow30 init 1 SlidePanel30 引数なし Slideshow30 init 2 start 1 i = 1 str = コスモス1 SlidePanel30 str = コスモス1 start 2 SlidePanel30 init paintComponent java.lang.NullPointerException at SlidePanel30.paintComponent(Slideshow30.java:148) 7 期待している動きは、 Slideshow30クラス init-actionPerformed-run-start を経て SlidePanel30クラス init-paintComponent そしてrunから繰り返す。 実際は、最初は、actionPerformed-runが無視されて、 init-start-paintComponentと入る。 8 しかし、ImageIconオブジェクトを生成するstartを経てpaintComponentに入るから、i の初期値を1 にしておけば、slide1の写真が表示されてもいいのだが、実際にはやはりNullPointerExceptionとなる。 newとImageIconオブジェクトを引数としたSlidePanel30コンストラクタで、ImageIconオブジェクトを 最初にpaintComponentに渡したつもりだが、それがうまくないのかもしれない。
4 Slideshow.java [実行結果] スライドショー (6-1のSlideshow.htmlと同じファイル名だが、別のディレクトリにおいている)。 [ソースプログラム] Slideshow.java 9 ここで、6-1のように、最初に全ての写真ファイルのImageIconオブジェクトを作成してしまう方法を トライしてようやく成功したと思っていたが、内部クラスを使って書き直してしまった。 再現しようといろいろ試みだが、全て失敗。錯覚だったか!!
A 引数なしのSlidePanelはstring = null。 1 contentPane.add(slidepanel,BorderLayout.CENTER); などを入れるため、 SlidePanel slidepanel=new SlidePanel();と引数なしのコンストラクタを作って 呼ぶと、そのためか、paintComponentに入ってしまい、stringもimgiconもnullと なる。 (Slideshow30.javaのエラーも同じなのだろう)。 SlidePanel 引数なし(引数なしのコンストラクタ、次が引数つきコンストラクタ) SlidePanel i = 0 string = コスモス(昭和記念公園 2003) height = 600 start i = 0 str2 = コスモス(昭和記念公園 2003) init i = 0 string = コスモス(昭和記念公園 2003) height = 600 paintComponent i = 0 string = null height = 0 java.lang.NullPointerException: string is null B 引数なしのSlidePanelのコンストラクタをやめる。 contentPane.add(slidepanel,BorderLayout.CENTER);などもその後に 移す。これで、stringやimgiconのnullはなくなり、最初の写真と説明は出る。サウンドも鳴る。 しかし、SlidePanelのinitからpaintComponentに入らなくなった。repaintがあるにもかかわらず。 initをupdateに変えても変わらず。paintComponentに入るのは、最初とアプレットを閉じたときだけ。 SlidePanel i = 0 string = コスモス(昭和記念公園 2003) height = 600 start i = 0 str2 = コスモス(昭和記念公園 2003) paintComponent i = 0 string = コスモス(昭和記念公園 2003) height = 600 SlidePanel i = 0 string = コスモス(昭和記念公園 2003) height = 600 start i = 0 str2 = コスモス(昭和記念公園 2003) SlidePanel i = 1 string = コスモス1 height = 600 start i = 1 str2 = コスモス1 SlidePanel i = 2 string = コスモス2 height = 600 start i = 2 str2 = コスモス2 paintComponent i = 0 string = コスモス(昭和記念公園 2003) height = 600 C 引数なしのSlidePanelのコンストラクタをやめる(その2)。 SlidePanel slidepanel=new SlidePanel(i,images[0],str[0],height);とする。 これで最初の写真が出る。 SlidePanel のinitまではいっても、paintComponentに行くのは、一度だけというのが不可解。 (initをupdateやstartとしても同じ、また、その呼び出し位置をコンストラクタの中においても同じ。) C:\HPBasic\Toppage-sample3\MySwing\Slideshow100>appletviewer Slideshow.java SlidePanel i = 0 string = コスモス(昭和記念公園 2003) height = 600 SlidePanel init SlidePanel i = 0 string = コスモス(昭和記念公園 2003) height = 600 SlidePanel init start i = 0 str2 = コスモス(昭和記念公園 2003) paintComponent i = 0 string = コスモス(昭和記念公園 2003) SlidePanel i = 0 string = コスモス(昭和記念公園 2003) height = 600 SlidePanel init start i = 0 str2 = コスモス(昭和記念公園 2003) SlidePanel i = 1 string = コスモス1 height = 600 SlidePanel init start i = 1 str2 = コスモス1 D repaint()を直接、Slideshowのstartに書く。 それで、paintComponentに入るようになったが、string=0のままで変わらない。 C:\HPBasic\Toppage-sample3\MySwing\Slideshow100>appletviewer Slidesh SlidePanel i = 0 string = コスモス(昭和記念公園 2003) height = 600 SlidePanel i = 0 string = コスモス(昭和記念公園 2003) height = 600 start i = 0 str2 = コスモス(昭和記念公園 2003) paintComponent i = 0 string = コスモス(昭和記念公園 2003) SlidePanel i = 0 string = コスモス(昭和記念公園 2003) height = 600 start i = 0 str2 = コスモス(昭和記念公園 2003) paintComponent i = 0 string = コスモス(昭和記念公園 2003) SlidePanel i = 1 string = コスモス1 height = 600 start i = 1 str2 = コスモス1 paintComponent i = 0 string = コスモス(昭和記念公園 2003)
5 Slideshow50.java インスタンス・オブジェクト変数で値を受けとる。 [ソースプログラム] Slideshow50.java 上記の2から4まではいずれも、コンストラクタの引数の形で値を渡そうとしたが、趣を変えて、 写真画像、説明文、アプレットの高さをインスタンス・オブジェクト変数で受け取ろうとしたが、 それらの初期値しか受けとれず失敗。なぜだろう? string=nullでエラーになる。 6 Slideshow500.java インスタンス・メソッドで値を受けとる。 [ソースプログラム] Slideshow500.java そこで、getimg,getstr,getheightとして、メソッドを使おうとしてもだめ。thread起動後、getimgなどを 通らないためかと考え、startメソッドの中でも呼んだが、それでもだめだった。 heightにいたっては、initで600となるのに、getheightでは初期値の0。同じクラスの中で値が伝わら ないのはなぜ?
1 内部クラスとして成功 1 別クラスSlidePanelを内部クラスにする方法でやってみるとあっさり成功。引数渡しも不要。 それが6-1のSlideshow。 2 その方法をSlideshow10やSlideshow30に適用して、それぞれ、Slideshow1、Slideshow3とした。 いずれも成功。 [Slideshow1 実行結果] スライドショー1 ソースプログラム Slideshow1.java [Slideshow3 実行結果] スライドショー3 ソースプログラム Slideshow3.java 引数なしのSlidePanelのコンストラクタは使っているが、そのために、準備のないまま、paintComponent に入ることもなければ、repaint()から、素直にpaintComponentに入っている。 失敗した8-1,8-2との違いは、SlidePanelのコンストラクタは引数なしの暗黙のものというだけに思えるのだが。 2 Slideshowのクラス変数で値を受けとる。 オブジェクト変数で受け取れなかった写真画像、説明文、アプレットの高さをクラス変数としてあっさり解決。 別クラスSlidePanelを内部クラスとせずに成功した唯一の例。 [Slideshow5 実行結果] スライドショー5 ソースプログラム Slideshow5.java これも上記、Slideshow1,3 のコメントに書いたことと同じことがいえる。 3 start,stopボタンも写真説明もない単純なもの [Slideshow4 実行結果] スライドショー4 ソースプログラム Slideshow4.java