2012-06-05 30 views
5

我想要一個真正簡單的方法來播放來自Java應用程序的mp3文件。經過一番研究,我發現最新版本的Java 7 SE與JavaFX一起打包,所以我想我會試試。這個問題不是關於播放mp3文件,而是關於讓JavaFX以一種行爲良好的方式工作。JavaFX 2.1和線程? - 或者 - 優雅地結束JavaFX應用程序?

所以,在我的第一個實驗中使用JavaFX,我使用了一些代碼,在後建議計算器(see here)創建的,從本質上講,下面的測試程序:

import javafx.application.Application; 
import javafx.stage.Stage; 
import javafx.scene.media.Media; 
import javafx.scene.media.MediaPlayer; 

public class progtest extends Application 
{ 

    /*---------------------------------------------------------*\ 
     FUNCTION: main() 
    \*---------------------------------------------------------*/ 
    public static void main(String args[]) 
    { 

     launch(args); 

    } /* END: main() */ 

    /*---------------------------------------------------------*\ 
     FUNCTION: start() 
    \*---------------------------------------------------------*/ 
    @Override 
    public void start(Stage stage) 
    { 

     Media medMsg 
      = 
      new Media(getClass().getResource("msg.mp3").toExternalForm()); 
     MediaPlayer medplMsg = new MediaPlayer(medMsg); 
     medplMsg.play(); 

     System.out.println("Here.\n"); 

    } /* END: start() */ 

} 

(此略比更復雜我原來的測試程序:這個版本從jewelsea響應前面一個問題我張貼有關獲取所有(see here)運行程序提出的建議後,來到約)

編譯這段代碼我用:

javac -cp "c:\Program Files\Oracle\JavaFX 2.1 Runtime\lib\jfxrt.jar";..\bin -d ..\bin ..\src\progtest.java 

而且,跑我走進我的.. \ bin目錄和使用的代碼:

java -cp .;"c:\Program Files\Oracle\JavaFX 2.1 Runtime\lib\jfxrt.jar" progtest 

該程序運行並播放片段播放。但是,除非我執行Ctrl-C,否則程序不會返回到命令提示符。

這種行爲看起來像某種線程問題。我已經多次看到這種行爲與Java線程一起工作(不幸的是,它們存在真正的問題,允許從程序中優雅地退出)。

所以,我想,也許如果我把代碼放在它自己的線程中,然後在線程結束時結束程序的主線程,事情就沒有問題。 (我可以看到,這並不完全是個有說服力的思想,但無論如何,我想我會嘗試一下。)所以,我寫的代碼的下面第二個版本:

這裏是主線程:

import javafx.application.Application; 
import javafx.stage.Stage; 
import Msg.*; 

public class progtest2 extends Application 
{ 

    /*---------------------------------------------------------*\ 
     FUNCTION: main() 
    \*---------------------------------------------------------*/ 
    public static void main(String args[]) 
    { 

     launch(args); 

    } /* END: main() */ 

    /*---------------------------------------------------------*\ 
     FUNCTION: start() 
    \*---------------------------------------------------------*/ 
    @Override 
    public void start(Stage stage) 
    { 

     Msg msgTime = new Msg(); 
     msgTime.passClass(getClass()); 
     msgTime.start(); 

     try 
     { 
      msgTime.join(); 
     } 
     catch (InterruptedException e) 
     { 
     } 

     System.out.println("Here.\n"); 

    } /* END: start() */ 

} 

這裏是爲消息線程實際上應該播放MP3文件的代碼:

package Msg; 

import KeyIO.*; 
import javafx.application.Application; 
import javafx.scene.media.Media; 
import javafx.scene.media.MediaPlayer; 

public class Msg extends Thread 
{ 

    private Class classRt = null; 

    /*--------------------------------------------------------*\ 
     FUNCTION: passClass() 
    \*--------------------------------------------------------*/ 
    public void passClass(Class rt) 
    { 

     classRt = rt; 

    } /* END: passClass() */ 

    /*--------------------------------------------------------*\ 
     FUNCTION: run() 
    \*--------------------------------------------------------*/ 
    public void run() 
    { 

     Media medMsg 
      = new Media(classRt.getResource("msg.mp3").toExternalForm()); 
     MediaPlayer medplMsg = new MediaPlayer(medMsg); 
     medplMsg.play(); 

     System.out.println("Leaving Msg thread.\n"); 

    } /* END: run() */ 

} 

(我建立並運行使用相同的命令,這些文件(比照重新文件名和類名)同上。 )

該程序運行並播放mp3文件。在您聽到該文件之前,您會看到「離開消息線程」。然後「Here。」,你可以看到它們分別來自Msg線程和主線程。但是,該計劃再次沒有結束。我必須按Ctrl-C返回到命令提示符。

我在主線程末尾放了一個System.exit()調用,看看這個行爲是什麼。行爲是沒有聽到剪輯。看起來像System.exit()調用結束了播放剪輯之前的過程。因此,接下來我嘗試在System.out.println(「Here。\ n」)之間放置以下幾行代碼:和System.exit()的調用我做:

System.out.print("Press ENTER to end..."); 
KeyIO.ReadLine(); 

(KeyIO是我只是做簡單的鍵盤輸入輸出做了一個類的細節是不是真的與此有關。)

我想這會阻止主線程前進,直到播放剪輯。

但是,沒有。相反,剪輯沒有播放。當我按下ENTER時,程序退出而不播放剪輯。

好的,現在我離開了那個鍵盤輸入的阻止代碼,但是我取出了System.exit()調用。現在播放了音頻剪輯,但程序沒有再次結束。

Urgh!

任何想法如何優雅地得到它的工作方式,它是明顯的一種會希望它的工作?我只想打個電話來播放剪輯,然後我想能夠結束該節目。

預先感謝您!

回答

8

在第一個progtest類中,您不創建窗口,因此不會調用關閉最後一個窗口的implicitExit動作。這意味着程序將繼續運行,直到您調用應用程序的退出方法,而您不這樣做。

要讓程序在您的mp3播放完畢後退出,請致電mediaPlayer.setOnEndOfMedia(runnable),並在可運行的回調中調用Platform.exit()方法。

medplMsg.setOnEndOfMedia(new Runnable() { 
    @Override public void run() { 
    Platform.exit(); 
    } 
}); 

在你的問題中的所有其他線程的東西是不需要的(並且不解決你的問題......)。我不會建議使用自定義線程,除非你真的需要它(你不這樣做)。

JavaFX的2.2增加了以下API:

Platform.setImplicitExit(boolean implicitExit) 

設置implicitExit屬性爲指定的值。如果 屬性爲true,則在最後一個窗口關閉時,JavaFX運行時將隱式關閉; JavaFX啓動程序將調用 Application.stop()方法並終止JavaFX應用程序線程。 如果此屬性爲false,則即使在最後一個窗口關閉後,應用程序仍會正常運行 ,直到應用程序 調用exit()。默認值是true。

這應該給你一些線索,你有問題。

+0

非常好!它像一個魅力。我將在下面發佈整個代碼。謝謝你jewelsea!很有幫助。它給了我很多關於我如何能夠在未來自己找出這些東西的見解。謝謝。 –

0

對我自己的問題的這個答案是給出一個最終解決jewelsea在這個線程中出現的問題以及我在原始文章中提到的另一個問題的代碼的明確例子。

好了,下面的代碼工作(和jewelsea在評論該線程是不必要的,旁邊的任何點是在這裏):

import javafx.application.Application; 
import javafx.application.Platform; 
import javafx.stage.Stage; 
import javafx.scene.media.Media; 
import javafx.scene.media.MediaPlayer; 

public class progtest6 extends Application 
{ 

    /*---------------------------------------------------------*\ 
     FUNCTION: main() 
    \*---------------------------------------------------------*/ 
    public static void main(String args[]) 
    { 

     launch(args); 

    } /* END: main() */ 

    /*---------------------------------------------------------*\ 
     FUNCTION: start() 
    \*---------------------------------------------------------*/ 
    @Override 
    public void start(Stage stage) 
    { 

     Media medMsg 
      = 
      new Media(getClass().getResource("msg.mp3").toExternalForm()); 
     MediaPlayer medplMsg = new MediaPlayer(medMsg); 
     medplMsg.setOnEndOfMedia(new Runnable() { 
      @Override 
      public void run() 
      { 
       Platform.exit(); 
      } 
     }); 
     medplMsg.play(); 

     System.out.println("Here.\n"); 

    } /* END: start() */ 

} 

謝謝jewelsea。