//File: SoundWin.java --- @CopyLeft by tsaiwn@csie.nctu.edu.tw ///Test Open a URL window, playing Song in Applet and Application /// Also show you how Applet works through tracing each function /// More Files need in addition to the SoundWin.java : /// howcome.au, laugh.au, welcome.wav and gigi.jpg , gigib.jpg /// All files for this example can be found here: // http://www.csie.nctu.edu.tw/~tsaiwn/course/java/examples/soundwin/ /// //To compile this program: // javac -encoding Big5 -target 1.1 SoundWin.java // //You can try this URL: // http://www.csie.nctu.edu.tw/~tsaiwn/course/java/ // examples/soundwin/testsw.html // //This program demostrate: // (1) How to open another URL. Either from Applet or from Application. // (2) How to play Sound Files. Either from Applet or from Application) // (3) Plus, We also include an Image Button in this demo. // And, use a thread to act as a timer to perform the hint task. // It will show a message that rolling to left on the panel. // While another message is shown on a flash manner. // (會有一個跑馬燈 以及一列閃爍的提示訊息) // (4) 若當作 Application 來 Run, 會看到一大堆跑過各主要程式的訊息, // 包括 main, init, start, repaint, update, paint 等 // (5) 若當 Applet (由 Browser 中看), 則該些訊息在 Java Console(主控台), // 可在 Browser 的 工具 ==> Java 主控台 把 Java 的 Consol 叫出來觀看. // (請check 你的 Browser 確認你是用 Sun 的 JVM 還是用 Microsoft VM ?) // (6) 為免太多訊息, 在第 58 次叫 paint()之前若是由 Hinter 引起的訊息則 // 不顯示; 第 59 次開始自動顯示, 但你可以按 STOP 按鈕使其不顯示或 // 切回要顯示 (toggle). 不過非 Hinter (負責跑馬燈和閃爍訊息) 所引起 // 的訊息時則一定會顯示. // // This Java program can be run both as Applet and as Application. // To run as an Application: java SoundWin ////////// /***** When used as an Applet, embed it in an HTML file as following:
************************/ import java.applet.*; import java.awt.*; import java.awt.event.*; import java.net.*; import java.text.*; import javax.swing.ImageIcon; // for ImageButton import javax.swing.JButton; public class SoundWin extends Applet implements ActionListener { static final private int WIDTH=358, HEIGHT=288; final private static int SHOW_HINT_INTERVAL = 588; // milli seconds static final String WELCOME_NAME = "welcome.wav"; static final String SONG_NAME = "howcome.au"; static final String SONG2_NAME = "howcome.wav"; static final String SONG_BUTTON_CAPTION = "點唱 情字這條路"; static final String LAUGH_AUDIO_NAME = "laugh.au"; static final String LAUGH_BUTTON_CAPTION = "HaHa大笑"; static final String GIGI_PIC_FILENAME = "gigi.jpg"; static final String GIGI_PIC_FILENAME2 = "gigib.jpg"; static final String WEB_BUTTON_CAPTION = "連到奇摩"; static final String TASK_BUTTON_CAPTION = "Manager"; static final String WEB_LOCATION = "http://tw.yahoo.com"; String SONG_LOCATION = "http://www.csie.nctu.edu.tw/~tsaiwn/audir/"; String flashLocation = // may be changed to other at RUN Time "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" + "movie%ad%ec%a9l%c0%c9/4-%af%ab%c0J%abL%abQ/4.swf"; //Some funny flash links in my directory: NCTU_CSIE_WEB/~tsaiwn/flash/ //We will use a Random number to choose one from these URLs (.swf) String swfAry[ ] = { // array for .swf flash file "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" + "movie%ad%ec%a9l%c0%c9/4-%af%ab%c0J%abL%abQ/4.swf", "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" + "movie%ad%ec%a9l%c0%c9/2-%ad%b8%b5%be%a4%a7%b9%da/2.swf", "http://www.csie.nctu.edu.tw/~tsaiwn/flash/02-GGL-fun/GGL_02.swf", "http://www.csie.nctu.edu.tw/~tsaiwn/mouse/catch_cursor.htm", "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" + "movie%ad%ec%a9l%c0%c9/3-%b1%a1%b8%d6/3.swf", "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" + "effect%ad%ec%a9l%c0%c9/36-%b7%cf%a4%f5%a4@/36.swf", "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" + "effect%ad%ec%a9l%c0%c9/25-3Dengine/25.swf", "http://www.csie.nctu.edu.tw/~tsaiwn/flash/" + "effect%ad%ec%a9l%c0%c9/61-%b7%c6%b9%ab%afS%ae%c4%a4Q/61.swf", "http://www.csie.nctu.edu.tw/~tsaiwn/flash/", "http://www.csie.nctu.edu.tw/~tsaiwn/mouse/catch_cursor.htm", "http://www.csie.nctu.edu.tw/~tsaiwn/course/introcs/ghost/" }; static int visitCount = 0; // control which swf in swfAry[] to show static final Font myFont = new Font("標楷體", Font.BOLD, 18); Toolkit toolkit; Frame f; Applet ap = null; TextField tSouth = null; // so the Applet can see this AudioClip song; Image giGiImage, giGiImage2; ImageIcon giGiIcon; Button bWeb = new Button( WEB_BUTTON_CAPTION ); Button bSong = new Button( SONG_BUTTON_CAPTION); Button bLaugh = new Button( LAUGH_BUTTON_CAPTION ); // replaced by bGiGi JButton bGiGi = new JButton( LAUGH_BUTTON_CAPTION ); //// bGiGi will use ImageButton through ImageIcon giGiIcon Button bStop = new Button("STOP"); Button bFlash = new Button("FLASH"); Button bTaskMgr = new Button( TASK_BUTTON_CAPTION); /// ///// we need a thread act as timer to show hint msg periodically protected Hinter hinter; // a thread to flash the hint message String status = "---"; static void printMsg(String s) { try{ System.err.println(s); System.err.flush( ); // need flush? } catch (Exception e) {;} // ignore all errors } // printMsg 方便使用而已 static private boolean isApplication = false; // Application or Applet public static void main( String s[ ]) { // for Application only printMsg("Run the main( ) program..." ); Frame f = new Frame("Window 2004"); isApplication = true; // to indicate that this is an Application // an Applet will NOT run this main( ) function SoundWin a = new SoundWin( ); // new the Applet (simulate Browser) a.ap = a; // a.ap points to the Applet it self a.f = f; // a.f points to the Frame f created in Application main() TextField t2 = new TextField("This is an Application." + " Press Enter Here will Quit."); a.tSouth = t2; // so the Applet can see this t2 as tSouth // Applet won't run main( ); tSouth will equales null f.add(a, BorderLayout.CENTER); // put the Applet in the Frame f TextArea t = new TextArea("這\n是\n獨\n立\n應\n用\n程\n式",2,3); t.setEditable(false); t.setBackground(Color.green); t.setLocale(java.util.Locale.CHINESE); t.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); t.setFont( new Font("標楷體", Font.BOLD, 24) ); f.add(t, BorderLayout.EAST); // a text board on the Right Side t2.setFont( new Font("Ludica Console", Font.BOLD, 24) ); t2.setEditable(false); t.setBackground(Color.blue); t2.setForeground(Color.red); // 紅色字体 f.add(t2, BorderLayout.SOUTH); // t 和 t2 只是秀出這是 Application a.init( ); // simulate Applet behavior a.start( ); // simulate Applet behavior a.sayHello(WELCOME_NAME); // Application say Hello on Console /// resizing the window for fun int szW[ ] = { 988, 58, 88, 888, 98, 108, 128, 149, 58, 158 }; int szH[ ] = { 58, 888, 666, 888, 18, 28, 38, 58, 16, 68 }; for(int i=0; i< szW.length; ++i) { // resize the window for fun try { try { Thread.sleep(368); } catch (InterruptedException e) {;} f.setSize(WIDTH+ szW[i], HEIGHT+ szH[i]); f.setVisible(true); f.validate( ); } catch(Exception e2) {;} } // for printMsg("=== .. main( ) finish. ===" ); printMsg(" ====================" ); printMsg(" ==============" ); printMsg(" ========\n" ); } // main( ) ends here public SoundWin( ) { // Constructor, remember SoundWin extends Applet if(ap==null) ap = this; // Let ap points to myself first } private void decorateFrame( ) { // some funny Layout Label b2a = new Label("假"); Label b2b = new Label("做"); Label b2c = new Label("真"); Label b2d = new Label("時"); b2a.setFont(new Font("標楷體", Font.BOLD, 18)); b2b.setFont(myFont); b2c.setFont(myFont); b2d.setFont(myFont); Label bx = new Label(" "), by = new Label(" "), bz = new Label(" "); bx.setFont(myFont); by.setFont(myFont); bz.setFont(myFont); Panel pRight = new Panel(new GridLayout(5,2, 1,1)); pRight.setLocale(java.util.Locale.CHINESE); pRight.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); Label ya = new Label("真"); Label yb = new Label("亦"); Label yc = new Label("假"); ya.setFont(myFont); yb.setFont(myFont); yc.setFont(myFont); pRight.add(b2a); pRight.add(bx); pRight.add(b2b); pRight.add(by); pRight.add(b2c); pRight.add(ya); pRight.add(b2d); pRight.add(yb); pRight.add(bz); pRight.add(yc); ap.add(pRight, BorderLayout.EAST); // Panel pSouth = new Panel(); // default LayoutManager is FlowLayout pSouth.add(bSong); pSouth.add(bWeb); pSouth.add(bFlash); pSouth.add(bTaskMgr); ap.add(pSouth,"South"); // Panel pLeft = new Panel(new GridLayout(2,1,5,28)); // 2 row, 1 column pLeft.add(bGiGi); pLeft.add(bStop); ap.add(pLeft, "West"); // 裝了兩個 Button 的 Panel 放左邊 } // decorateFrame public void init( ) { toolkit = Toolkit.getDefaultToolkit(); // for later use printMsg("Run the init( ) in Applet." ); bGiGi = new JButton( LAUGH_BUTTON_CAPTION ); try { // Application 中讀取 Image 方法與 Applet 中不同 if(isApplication) { // use my function newImage to load Image file giGiImage = newImageBoth(GIGI_PIC_FILENAME); } else giGiImage = newImageBoth(GIGI_PIC_FILENAME); //giGiImage = getImage(new URL( getCodeBase()+ GIGI_PIC_FILENAME)); giGiIcon = new ImageIcon(giGiImage); bGiGi = new JButton(giGiIcon); // wrap GiGI's picture if(isApplication) { giGiImage2 = newImageBoth(GIGI_PIC_FILENAME2); } else giGiImage2 = newImageBoth(GIGI_PIC_FILENAME2); //giGiImage2 = getImage(new URL( getCodeBase()+ GIGI_PIC_FILENAME2)); // giGiImage2 will be used to flip pic when mouse enters bGiGi // see the MouseEvent handler (class Amigo) below } catch (Exception e) { ; } bGiGi.setCursor( new Cursor(Cursor.HAND_CURSOR) ); bStop.setCursor( new Cursor(Cursor.HAND_CURSOR) ); //ap.setLayout(new BorderLayout( ) ); setLayout(new BorderLayout( ) ); // change the Applet's LayoutManager decorateFrame( ); // decorate the window with some Chinese character /// bStop.setBackground(Color.red); bStop.setFont( new Font("Ludica Console", Font.BOLD, 20) ); bSong.setBackground(Color.pink); bWeb.setBackground(Color.green); //// Register necessary Event Listener to handle events bWeb.addActionListener(this); // register with ActionListener bFlash.addActionListener(this); bTaskMgr.addActionListener(this); bSong.addActionListener(this); bGiGi.addActionListener(this); bGiGi.addMouseListener(new Amigo( )); bStop.addMouseListener(new Amigo( ) ); bStop.addActionListener(this); if(tSouth != null) tSouth.addActionListener(this); ap.setSize(WIDTH, HEIGHT); ap.setVisible(true); hinter = new Hinter(SHOW_HINT_INTERVAL); //a Thread acts as a timer hinter.start( ); // start the Timer thread to toggle hint message status = "...Press the Button to test .."; //repaint( ); // not necessary , 我們的 Hinter 內會叫 repaint } // init() public void start( ) { printMsg("Run the start( ) in Applet." ); super.start( ); // 別忘了上層的 start( ) } public void stop( ) { // 離開 Applet 網頁時執行 printMsg(" - - -stop( ) called === " ); super.stop( ); } public void validate( ) { // don NOT forget super class's validate printMsg(" ! validate( ) called === " ); super.validate( ); } protected int nUpdate = 0; // number of visit to the update( ); public void update(Graphics g) { ++nUpdate; //////////////// try{ if( ! hintMode) { printMsg(" update( ) called ::: "+ nUpdate + ", Repaint :" + nRepaint + ", Update: "+nUpdate + ", Paint :" + nPaint); } else { // special processing for hintMode if( nPaint > 58) { // hide paint message if count <= 58 if(showHintPaint) printMsg(" update( ) called ::: "+ nUpdate + ", Repaint :" + nRepaint + ", Update: "+nUpdate + ", Paint :" + nPaint + " --- by Hinter. "); } // if nPaint>58 } // if }catch(Exception ex){;} // forget this Error /// /// 上層的 update 會先把 Applet 清除 (clear) super.update(g); // 別忘了上層的 update() , 它會叫用 paint( ) /// 可故意把這 super.update(g) 暫時 註解掉測試看看 } protected int nRepaint = 0; // number of visit to the repaint( ); public void repaint( ) { ++nRepaint; /// /// /// /// /// keep quiet before nPaint == 59 if( ! hintMode) { printMsg(" repaint( ) called - -- --- ----- "+ nRepaint + ", Update: "+nUpdate + ", Paint :" + nPaint); } else { // special processing for hintMode if( nPaint > 58) { // hide paint message if count <= 58 if(showHintPaint) printMsg(" repaint( ) called - -- --- ----- "+ nRepaint + ", Update: "+nUpdate + ", Paint :" + nPaint + " by Hinter. "); } // if nPaint>58 } // if ///可故意拿掉下列再測試看看 super.repaint(); // 別忘了上層的 repaint() , 它會叫 update( ) } protected int nPaint = 0; // number of visit to the paint( ); // we should NOT call paint directly public void paint(Graphics g) { ++nPaint; if( ! hintMode) { printMsg(" paint( ) is called: "+ nPaint + ", Repaint :" + nRepaint + ", Update: "+nUpdate + ", Paint :" + nPaint); } else { // special processing for hintMode if( nPaint > 58) { // hide paint message if count <= 58 if(showHintPaint) printMsg(" paint( ) is called : "+ nPaint + " by Hinter. Press STOP to toggle Hinter paint message."); } // if nPaint>58 } // if g.setColor(Color.red); g.setFont( new Font("標楷體", Font.BOLD, 14) ); g.drawString( status + " ", 88, 128); if(hintMode) { // is in hintMode switch( (int)hinter.showFlag%8/2 ) { case 0: g.drawString( "/ ..按 FLASH 每次不同喔 !", 108, 228); bFlash.setBackground(Color.orange); break; case 1: g.drawString( "- !! ", 108, 228); bFlash.setBackground(Color.pink); break; case 2: g.drawString( "\\ ..按 FLASH 每次不同喔 !", 108, 228); bFlash.setBackground(Color.magenta); break; case 3: g.drawString( "| !! ", 108, 228); bFlash.setBackground(Color.white); break; } // switch if( hinter.showFlag <= 18 ) // 開始時都秀出 g.drawString( " ..按 FLASH 每次不同喔 !", 108, 228); } rollMessage(g); // 太長了切出去另一個 function } private void rollMessage(Graphics g) { int showLen = 18; // show characters windwow size int len = msgLength; int p = (int) (hinter.showFlag % msgLength); int pEnd = p + showLen -1; String s; if(pEnd < msgLength ){ s = msg.substring(p, pEnd); // 這種不斷改變 s 字串的方法不好 }else{ // 可改用 StringBuffer 比較不浪費資源 int pLen = msgLength - p; s = msg.substring(p, msgLength-1) + msg.substring(0, showLen-pLen); } g.drawString( s, 108, 58); } public void actionPerformed (ActionEvent evt) { Object who = evt.getSource( ); // who fires the ActionEvent ? printMsg("ActionEvent: " + who); if(who == bWeb) { // bWeb Button was clicked bWeb.setBackground(Color.red); // Let user know he press me try { openWebWindow( ); } catch(Exception e) {;} } else if(who == bSong) playSong( ); //play song: 情字這條路 else if(who == bGiGi) makeLaugh( ); //play laugh.au else if(who == bFlash) { openFlashURL( ); } else if(who == bTaskMgr) { runTaskManager( ); } else if(who == tSouth) System.exit(0); // special in Application else if(who == bStop) { // try to Stop the Audio, including Laughing if(song != null) song.stop( ); // stop playing the song status = "...Press the Button to test .."; //repaint( ); /// toggle the showHintPaint mode every time you press the STOP if(showHintPaint) showHintPaint=false; else showHintPaint=true; //System.exit(0); // enable this line if you want to Quit fot this } // else if } // actionPerformed() void runTaskManager( ) { // Application only printMsg("Try to run the Task Manager (taskmgr ) " ); try { if(isApplication) { // utilize the Runtime exec function try { // 注意格式, 因字串中含有 " 雙引號 " Runtime.getRuntime().exec( "cmd /c \"taskmgr" + "\" " ); } catch (Exception e95){ } // Win95/98 ? } // } catch (Exception e) {; } } // run taskmgr void openWebWindow( ) { // note that different when in Application printMsg("Try to open " + WEB_LOCATION); try { if(isApplication){ // utilize the Runtime exec function try { // 注意格式, 因字串中含有 " 雙引號 " Runtime.getRuntime().exec( "cmd /c \"start " + WEB_LOCATION +"\" " ); } catch (Exception e95){ // try Win 95/98 Runtime.getRuntime().exec( "start " + WEB_LOCATION ); //Win95/98中 start 是內建 } } else { // is Applet, we are in Browser, use showDocument( ) URL url = new URL(WEB_LOCATION); getAppletContext().showDocument(url, "_blank"); } // see AppletContext // _blank means in New Window } catch (Exception e) {; } } void openFlashURL( ) { // URL address String in String swfAry[ ] int n = (int)(Math.random( ) * 100); // 0..99 n = n % swfAry.length; if( visitCount++ == 0 ) n = 0; // first visit, show swfAry[0] if( visitCount == 2 ) n = 2; // GGL, second visit, show swfAry[2] if( visitCount == 3 ) n = 3; // [3] = play_hand_mouse on 3rd visit if( n == 0 && visitCount > 3 && visitCount < 8 ) n = visitCount % swfAry.length; // 第8次前不再秀swfAry[0]神鵰俠侶 try { flashLocation = swfAry[n]; } catch (Exception e) { n=2; } // 2 is GGL printMsg("Try to open " + flashLocation); try { if(isApplication){ try { // XP, NT Runtime.getRuntime().exec( "cmd /c \"start " + flashLocation + "\" "); } catch (Exception e98) { // try Win95/Win98 Runtime.getRuntime().exec( "start " + flashLocation ); } } else { URL url = new URL( flashLocation ); // a file in ~tsaiwn/... getAppletContext().showDocument(url, "_blank"); } // if } catch (Exception e) {; } } void openSong( ) { // use a Browser to open a Song URL printMsg("Try to open " +SONG_NAME + " in " + SONG_LOCATION); try { URL url = new URL( (SONG_LOCATION + SONG_NAME).trim() ); if(isApplication){ try { // XP, NT Runtime.getRuntime().exec( "cmd /c \"start " + url.toString( ) + "\" "); } catch (Exception e98) { // try Win95/Win98 Runtime.getRuntime().exec( "start " + url.toString( ) ); } } else { // Applet getAppletContext().showDocument(url, "_blank"); } // if } catch (Exception e) {; } } void playSong( ) { // play the AudioClip from a file or a URL printMsg("Playing.." + SONG_NAME); try { if(isApplication) { // after JDK 1.2 song = Applet.newAudioClip(new URL(newCodeBase( )+SONG_NAME)); }else{ song = getAudioClip(getCodeBase( ), SONG_NAME); } // if } catch ( Exception e ) { try{ // try-2, try tsaiwn URL try{ showStatus( ".. " + SONG_LOCATION + SONG_NAME); } catch ( Exception es ) {;} song = getAudioClip( new URL(SONG_LOCATION + SONG_NAME) ); status = ".. " + SONG_LOCATION + SONG_NAME + " "; } catch (Exception e2){ //System.err.println("Fail : "+e); try{ // try-3 song = getAudioClip( new URL("./" + SONG2_NAME ) ); status = " .. ./" + SONG2_NAME + "== = = "; } catch (Exception e3){ try { // try-4 song = Applet.newAudioClip( new URL(newCodeBase( ) + SONG2_NAME ) ); } catch ( Exception e4) { if(song==null) { openSong(); return; } // try my best } // try-4 } // try-3 } // try-2 } ; // // Play the sound if we got the AudioClip try { if(song != null) { song.play(); status = "...Playing " + SONG_NAME; } // if try { showStatus(" " + status ); } catch ( Exception es ) { ; } // on window's status line 狀態列 repaint( ); // draw message in the Applet Panel } catch ( Exception e ) { return; } } // playSong() void makeLaugh( ) { try { try{ showStatus(" :-) Laughing ..." ); } catch ( Exception es ) {;} playFile(LAUGH_AUDIO_NAME ); } catch ( Exception e ) {;} } void sayHello(String filename) { playFile(filename); } /********* void playFile(String filename) { try { if(isApplication) { URL base = newCodeBase(); song = Applet.newAudioClip(new URL(base+filename)); } else song = getAudioClip(getCodeBase(), filename); // Applet's song.play( ); status = "...Playing .." + filename; try{ showStatus(status); } catch ( Exception es ) {;} repaint( ); // show the status message on the Applet } catch (Exception e) {; } // ignore any error } *************/ //////////// /// public AudioClip newAudioBoth(String filename) { /// NOT static AudioClip audio = null; try { // 2004/06/08 Toolkit tkt = Toolkit.getDefaultToolkit( ); Class me = getClass( ); // get The class is running URL url = me.getResource(filename); audio = Applet.newAudioClip( url ); } catch (Exception e) { ; } return audio; } // newAudioBoth(filename) /// newAudio(url, filename) public AudioClip playFile(String filename) { AudioClip song = null; try { //song = getAudioClip(getCodeBase(), filename); // Applet's song = newAudioBoth(filename); // both OK song.play( ); } catch (Exception e) { return song; } // Let the caller know try { Thread.sleep(358); } catch (Exception e) {;} return song; } ///////////////////////// public URL newCodeBase( ) { // for Application to get CWD URL codeBase = null; // assume we can not get it try{ codeBase = new URL("file:" + System.getProperty("user.dir") + "/"); } catch ( Exception e ) { codeBase = getCodeBase( ); // where the Applet in // maybe it is an Applet, use getCodeBase() or getDocumentBase() } return codeBase; } /// get Image from a local file --- for Application (not Applet) public Image newImage(String filename) { Image img = null; try{ Toolkit tkt = Toolkit.getDefaultToolkit( ); img = tkt.getImage(filename); //for application only } catch ( Exception e ) { try { img = getImage(getCodeBase( ), filename); //for Applet } catch (Exception e2) {;} // ignore any error now } return img; } // newImage(filename) public Image getMyImage(String filename) { return newImage(filename); } // getMyImage(filename) /// public Image newImageBoth(String filename) { /// NOT static Image image = null; try { // 2011/04/02 good in Jar file Toolkit tkt = Toolkit.getDefaultToolkit( ); Class me = getClass( ); // get The class is running URL url = me.getResource(filename); image = tkt.getImage(url); } catch (Exception e) { ; } return image; } // newImageBoth(String ////// protected boolean hintMode = false; // control toggle display hint //////// paint( ) will check this variable protected boolean showHintPaint = true; // toggle paint message // an inner class to act as a Timer to show hint message // The uint of SHOW_HINT_INTERVAL is in milli seconds class Hinter extends Thread { protected volatile boolean shouldDie = false; // instead of stop( ); protected long showFlag = 0; protected int showInterval; // 記住傳來的 interval for hint message public Hinter(int interval) { showInterval = interval;} //Constructor //when new Hinter, please pass the interval to me as the argument. // the main part of a thread is the run( ) method public void run( ) { // Thread should implements the run( ) method while( ! shouldDie) { // Loop forever till the Master wants me to die try { showFlag++; } catch (Exception e){;} hintMode = true; repaint( ); // call it every showInterval milli-seconds hintMode = false; // so that won't affect other's call to paint try {sleep(showInterval); } catch(InterruptedException e){;} } // while } // run ///注意我們叫用 repaint( ); repaint() 會去叫我們的 paint(Graphics); /// 但是不是只有我們會叫到 paint( ); 因此要讓 paint( ) 知道是誰叫的 // 所以用一個 hintMode 這變數讓 paint( ) 檢查 } // MyTimer // another inner class Amigo to handle Mouse events //這個 Amigo 有能力處理部份 Mouse event class Amigo extends MouseAdapter { public void mouseEntered(MouseEvent e) { Object who = e.getSource( ); /* 查哪零件觸發 Mouse event? */ printMsg("MouseEvent: Entered " + who); /// if(who == bGiGi) { status = "... 按我就會大笑喔:-)"; giGiIcon.setImage(giGiImage2); bGiGi.updateUI(); } if(who == bStop) { status = "... 按 STOP 停止大笑或唱歌 ! "; } repaint( ); // it will call our paint( ) } public void mouseExited(MouseEvent e) { Object who = e.getSource( ); /* 查哪零件觸發 Mouse event? */ printMsg("MouseEvent: Exited " + who); /// if(who == bGiGi) { giGiIcon.setImage(giGiImage); bGiGi.updateUI(); } if(who == bGiGi || who == bStop) { status = " ... Press Buttons to Test"; } repaint( ); // it will call our paint( ) } } // class Amigo == means friend in spanish ///// end of inner class Amigo static int msgLength; // msgLength is used for Length of msg static final String msg = " Dear .. My Dear . . " + "我答應妳再也不會 打擾妳的生活 .. " + "捨不得妳 所以才會騙了妳也騙自己 .. " + "捨不得妳 雖然明知我的愛妳不珍惜 .. " + " - - - . . . 每當我最需要你 最想念你" + " 你總是缺席 ... " + "能不能讓我 陪著妳走 既然妳說 留不住妳 " + "回去的路 有些黑暗 擔心讓妳 一個人走" + " . . . . . .. " + "如果你要離開我 . . 我想我不會太難過 :-(" + " 也許會有一點點難過 ... 至少不會在你的面前難過 :-(" + " 也許會在你的面前難過 .. 至少不會在你的面前流淚 :-(" + " 也許會在你的面前流淚 . . 至少不會在你的面前哭出聲 :::-(" + " . . . . . . .. "; static { msgLength = msg.length( ); } // do this when class loaded /// Note that 注意 static Block 只在 class 被 Loaded 進 JVM 時 Run 一次 } // end of the whole class SoundWin