I have an application written in Swing, in which I want to use JavaFX's MediaPlayer for playing audio / sound files.
This is a condensed version of the main file:
class MyApp
{
private MyApp myApp;
private JFrame myFrame;
private Media media;
private MediaPlayer mediaPlayer;
public static void main(String[] args)
{
Runnable thread = new Runnable()
{
public void run()
{
myApp = new MyApp();
}
};
SwingUtilities.invokeLater(thread);
}
public void MyApp()
{
//this is called by SwingUtilities.invokeLater();
URL url = //getting URL to a sound file stored locally//;
media = new Media(url.toString() );
mediaPlayer = new MediaPlayer( media );
mediaPlayer.play();
myFrame = new JFrame(); //building swing UI here
}
This seems to work within Netbeans. However when Netbeans builds a .jar, and I try to run the .jar, I get an error log file built in the .jar directory containing some memory / threading errors.
Do I need to use the Platform.runLater() method to get this to work? Or is there anything else I'm doing wrong?
When interacting with JavaFX controls embedded in Swing app, definitely do this inside a Platform.runLater call, not a Swing.invokeLater call.
You should also ensure that the JavaFX system is initialized and (preferably) that the application is ackaged using the JavaFX packaging tools as mentioned in this post: Playing audio using JavaFX MediaPlayer in a normal Java application?.
While running some code that creates some JavaFX controls off the JavaFX thread works for most controls and even some interactions with some controls seem to work off the JavaFX thread sometimes, in practice I find it's not worth the risks and potentially obscure errors or race conditions you may encounter while doing so. JavaFX is designed with a single threaded interaction model with the UI in mind, so it is best to keep it that way using tools like Platform.runLater. Same is true of Swing with it's event dispatch thread. You need to keep the threaded interactions between these two frameworks separate.
Looking at the 5 lines you have in your MyApp code in your question, I have the following recommendations.
Doesn't matter what thread this is executed on as it does not interact with any framework:
URL url = //getting URL to a sound file stored locally//;
Makes use of JavaFX controls do should be wrapped in Platform.runLater:
media = new Media(url.toString() );
mediaPlayer = new MediaPlayer( media );
mediaPlayer.play();
Interacts with the Swing framework, so should be wrapped in Swing.invokeLater:
myFrame = new JFrame(); //building swing UI here
Note: just one runLater for the call is not enough, you also need to invokeLater the Swing jframe call from inside the runLater body after the MediaPlayer play call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With