2012-06-05 10 views
5

Chciałam naprawdę prosty sposób na odtwarzanie pliku mp3 z aplikacji Java. Po kilku badaniach odkryłem, że najnowsze wersje Java 7 SE są pakowane z JavaFX, więc pomyślałem, że spróbuję. To pytanie NIE dotyczy odtwarzania plików mp3, ale o tym, aby JavaFX działał w dobrze zachowany sposób.JavaFX 2.1 i wątki? -lub- Kończenie aplikacji JavaFX z gracją?

Tak, w moim pierwszym eksperymencie z JavaFX, kiedyś jakiś kod zasugerował we wpisie do stackoverflow (see here) i utworzoną zasadniczo następujący program testowy:

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() */ 

} 

(jest to nieco bardziej skomplikowane niż mój oryginalny program testowy: wersja ta powstała po sugestii jewelsea dokonanych w odpowiedzi na wcześniejsze pytanie napisałem o uzyskanie program działa na wszystkich (see here))

Aby skompilować ten kod użyłem.

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

A, aby uruchomić kod poszedłem do mojego .. \ bin i używany:

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

Ten program działa i odtwarza odtworzenia klipu. Jednak program nie powróci do wiersza polecenia, chyba że zrobię Ctrl-C.

To zachowanie wydawało się być kwestią wątku. Widziałem takie zachowanie wiele razy pracując z wątkami Java (które, niestety, mają prawdziwe problemy pozwalające na pełne wdzięku wyjścia z programów).

Pomyślałem więc, że być może, jeśli ustawię kod we własnym wątku, a następnie zakończę główny wątek programu, gdy skończy się ten wątek, wszystko będzie dobrze. (Widziałem, że nie było to całkowicie spójne myśli, ale mimo to, myślałem, że chciałbym spróbować.) Więc napisałem następujący drugą wersję kodu:

Oto główny wątek:

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() */ 

} 

a oto kod do wątku Msg że powinien właściwie odtworzyć plik 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() */ 

} 

(i zbudował i prowadził te pliki z tego samego polecenia (mutatis mutandis ponownie nazwy plików i classnames) jak powyżej.)

Program uruchamia i odtwarza plik mp3. Zanim usłyszysz plik, zobaczysz komunikat "Pozostawienie wątku Msg". a następnie "Tutaj", które jak widać, pochodzą odpowiednio z wątku Msg i głównego wątku. Ale znowu program się nie kończy. Muszę nacisnąć Ctrl-C, aby powrócić do wiersza poleceń.

Umieściłem wywołanie System.exit() na samym końcu głównego wątku, żeby zobaczyć, jakie będzie zachowanie. Zachowanie polegało na tym, że klip nie był słyszalny. Wyglądało na to, że wywołanie System.exit() zakończyło proces przed odtworzeniem klipu.

Następnie próbowałem umieścić następujące linie pomiędzy System.out.println ("Tutaj. \ N"); a System.exit() zadzwonić zrobiłem.

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

(KeyIO jest klasa I tworzył dla robią wyjście sygnału wejściowego klawiatury prostu Szczegóły nie są naprawdę istotne tutaj.)

Pomyślałem, że to po prostu zablokuje główny wątek od przejścia do następnego klipu.

Ale nie. Zamiast tego klip nie został odtworzony. Po naciśnięciu klawisza ENTER program zakończył się bez odtwarzania klipu.

OK, więc teraz zostawiłem kod blokujący wejście klawiatury, ale wyjąłem wywołanie System.exit(). Teraz klip audio został odtworzony, ale program się nie skończył.

Urgh!

Jakieś pomysły na to, jak z wdziękiem sprawić, by działało tak, jakby to było oczywiste? Chcę tylko zadzwonić, żeby zagrać w klip, a potem chcę mieć możliwość zakończenia programu.

Z góry dziękuję!

Odpowiedz

8

W pierwszej klasie progtest nie tworzy się okna, więc akcja implicitExit przy zamykaniu ostatniego okna nie jest wywoływana. Oznacza to, że program będzie działał, dopóki nie wywołasz metody wyjścia aplikacji, której nie robisz.

Aby program zakończył się po zakończeniu odtwarzania pliku mp3, zadzwoń pod numer mediaPlayer.setOnEndOfMedia(runnable), a wywoływane wywołanie zwrotne wywoła metodę Platform.exit().

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

Wszystkie inne wątki w twoim pytaniu nie są wymagane (i tak nie rozwiązują Twojego problemu ...). Nie zalecałbym używania niestandardowych wątków, chyba że naprawdę tego potrzebujesz (czego nie potrzebujesz).

JavaFX 2.2 dodaje się następujący api:

Platform.setImplicitExit(boolean implicitExit) 

Ustawia atrybut implicitExit do określonej wartości. Jeśli ten atrybut ma wartość true, środowisko wykonawcze JavaFX spowoduje niejawne zamknięcie, gdy ostatnie okno zostanie zamknięte; wyrzutnia JavaFX wywoła metodę Application.stop() i zakończy wątek aplikacji JavaFX. Jeśli ten atrybut ma wartość false, aplikacja będzie nadal działać normalnie nawet po zamknięciu ostatniego okna, dopóki aplikacja nie wywoła metody exit(). Wartością domyślną jest true.

To powinno dać ci wskazówkę co do problemów, które masz.

+0

Doskonale! To działa jak urok. Opublikuję cały kod poniżej. Dziękuję jewelsea !!! Bardzo pomocne. Dało mi to wiele informacji na temat tego, jak samemu mogę wymyślić niektóre z tych rzeczy w przyszłości. Dziękuję Ci. –

0

Ta odpowiedź na moje własne pytanie polega na podaniu ostatecznego przykładu kodu, który ostatecznie rozwiązał problem, który wynika z doskonałych odpowiedzi jewelsea w tym wątku, a także z drugiego, do którego odwołuję się w moim oryginalnym wpisie.

Ok, więc następujący kod pracował (a jewelsea rację komentując, że gwint jest niepotrzebna i przy każdym punkcie tutaj):

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() */ 

} 

Dziękuję jewelsea.