2012-06-05 11 views
5

Volevo un modo molto semplice per riprodurre un file mp3 da un'applicazione Java. Dopo alcune ricerche ho scoperto che le versioni più recenti di Java 7 SE sono state confezionate con JavaFX, quindi ho pensato di provare. Questa domanda NON riguarda la riproduzione di file mp3, ma l'idea di far funzionare JavaFX in modo corretto.JavaFX 2.1 e thread? -oppure- Terminare un'applicazione JavaFX con garbo?

Quindi, a mio primo esperimento con JavaFX, ho usato un po 'di codice suggerito in un post a StackOverflow (see here) e ha creato, in sostanza, il seguente programma di test:

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

} 

(Questo è un po' più sofisticato di il mio programma di test originale: questa versione è nata dopo suggerimenti da jewelsea fatte in risposta ad una precedente interrogazione che ho postato su come ottenere il programma in esecuzione a tutti (see here))

per compilare il codice che ho usato:.

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

E, per eseguire il codice sono andato nel mio .. \ bin e usato:

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

Questo programma corre e gioca la riproduzione del clip. Tuttavia, il programma non ritorna al prompt dei comandi a meno che non esegua un Ctrl-C.

Questo comportamento sembrava una sorta di problema di thread. Ho visto questo tipo di comportamento molte volte lavorando con i thread Java (che, purtroppo, hanno problemi reali che consentono di uscire agevolmente dai programmi).

Così, ho pensato, forse se inserisco il codice in una sua discussione e poi finisco il thread principale del programma quando finisce quel thread, le cose andrebbero bene. (Ho potuto vedere che questo non era del tutto un pensiero cogente, ma in ogni caso, ho pensato di provare.) Così, ho scritto il seguente secondo versione del codice:

Ecco il filo conduttore:

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

} 

e qui è il codice per il thread Msg che dovrebbe effettivamente giocare il file 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() */ 

} 

(ho costruito e corse questi file con lo stesso comando (mutatis mutandis re i nomi di file e classnames) come sopra.)

Il programma esegue e riproduce il file mp3. Prima di ascoltare il file, vedi "Leaving Msg thread." e quindi "Qui", che come potete vedere provengono rispettivamente dal thread Msg e dal thread principale. Ma, ancora, il programma non finisce. Devo premere Ctrl-C per tornare al prompt dei comandi.

Ho messo una chiamata System.exit() alla fine del thread principale solo per vedere quale sarebbe il comportamento. Il comportamento era che la clip non è stata ascoltata. Sembrava che la chiamata System.exit() terminasse il processo prima della riproduzione della clip.

Quindi, dopo ho provato a mettere le seguenti righe tra System.out.println ("Qui. \ N"); e lo System.exit() chiamata che ho fatto:.

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

(KeyIO è una classe che ho fatto solo per fare l'uscita input da tastiera semplicemente i dettagli non sono davvero rilevanti qui.)

Ho pensato che questo avrebbe semplicemente bloccato il thread principale da andare avanti fino a quando il clip riprodotto.

Ma, no. Invece, la clip non ha giocato. Quando premo INVIO, il programma esce senza riprodurre la clip.

OK, così ora ho lasciato il codice di blocco per l'input da tastiera, ma ho eliminato la chiamata System.exit(). Ora è stata riprodotta la clip audio, ma il programma non è terminato di nuovo.

Urgh!

Qualche idea su come far funzionare correttamente questo modo in cui è ovvio si vorrebbe che funzioni? Voglio solo fare una chiamata per riprodurre la clip, e poi voglio essere in grado di terminare il programma.

Grazie in anticipo!

risposta

8

Nella prima classe progtest, non si crea una finestra, quindi l'azione implicita Esci alla chiusura dell'ultima finestra non viene richiamata. Ciò significa che il programma continuerà a funzionare finché non chiami il metodo di uscita dell'applicazione, cosa che non fai.

Per far uscire il programma dopo che l'mp3 ha finito di suonare, chiamare mediaPlayer.setOnEndOfMedia(runnable) e nel richiamo eseguibile richiamare il metodo Platform.exit().

Tutte le altre discussioni nella tua domanda non sono richieste (e comunque non risolvono il problema ...). Non consiglierei di usare il threading personalizzato a meno che tu non ne abbia davvero bisogno (cosa che non lo fai).

JavaFX 2.2 aggiunge la seguente api:

Platform.setImplicitExit(boolean implicitExit) 

Imposta l'attributo implicitExit al valore specificato. Se questo attributo è true, il runtime JavaFX verrà arrestato implicitamente quando viene chiusa l'ultima finestra; il programma di avvio JavaFX chiamerà il metodo Application.stop() e terminerà il thread dell'applicazione JavaFX. Se questo attributo è falso, l'applicazione continuerà a funzionare normalmente anche dopo che l'ultima finestra è stata chiusa, finché l'applicazione chiama exit(). Il valore predefinito è true.

Questo dovrebbe darvi qualche indizio sui problemi che state avendo.

+0

Eccellente! Esso funziona magicamente. Pubblicherò l'intero codice qui sotto. Grazie, jewelsea !!! Molto utile. E mi ha dato un sacco di informazioni su come posso capire alcune di queste cose io stesso in futuro. Grazie. –

0

Questa risposta alla mia domanda è di dare un esempio definitivo del codice che alla fine ha risolto il problema che deriva dalle eccellenti risposte di jewelsea in questo thread e l'altro a cui mi riferisco nel post originale.

Okay, quindi il seguente codice ha funzionato (e jewelsea era proprio commentando che la filettatura è inutile e accanto a qualsiasi punto qui):

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

} 

Grazie jewelsea.