How to use JavaFX MediaPlayer correctly? - java

I'm writing a simple game and trying to play sounds but I can't get it to work when I create the Media object it throws IllegalArgumentException. I'm not much of a Java coder and any help will be appreciated.
Here is a sample code:
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
public class Main{
public static void main(String[] args) {
Media pick = new Media("put.mp3"); //throws here
MediaPlayer player = new MediaPlayer(pick);
player.play();
}
}
Obviously "put.mp3" exists and located in the correct directory, I checked the path using: System.out.println(System.getProperty("user.dir"));
what am I doing wrong here?

The problem is because you are trying to run JavaFX scene graph control outside of JavaFX Application thread.
Run all JavaFX scene graph nodes inside the JavaFX application thread.
You can start a JavaFX thread by extending JavaFX Application class and overriding the start() method.
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Media pick = new Media("put.mp3"); // replace this with your own audio file
MediaPlayer player = new MediaPlayer(pick);
// Add a mediaView, to display the media. Its necessary !
// This mediaView is added to a Pane
MediaView mediaView = new MediaView(player);
// Add to scene
Group root = new Group(mediaView);
Scene scene = new Scene(root, 500, 200);
// Show the stage
primaryStage.setTitle("Media Player");
primaryStage.setScene(scene);
primaryStage.show();
// Play the media once the stage is shown
player.play();
}
public static void main(String[] args) {
launch(args);
}
}

Ok thanks to #ItachiUchiha insight on the matter I was able to solve my problem, It seems that any code that uses javaFX must run from within javaFX application Thread but not every program has to use javaFX API. In short what I did is start my game from within the Application.start(Stage ps) like so:
import javafx.application.Application;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
new Game(9,9,BasicRobot.FACING.SOUTH, 19);
}
public static void main(String[] args) throws InterruptedException {
launch();
}
}
That way the Game class and everything it creates and uses can use javaFX. To play the sounds I created a Utils class:
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
public class Utils {
public static void playSound(String fileName){
Media m = new Media("file:///" + System.getProperty("user.dir").replace('\\', '/') + "/" + fileName);
MediaPlayer player = new MediaPlayer(m);
player.play();
}
}
and now all I have to do to play a sound is call Utils.playSound("fileName.mp3") from anywhere inside my Game.

Maybe this would work:
MediaMetadataRetriever mediaMetadataRetriever1 =new MediaMetadataRetriever();
mediaMetadataRetriever1.setDataSource(getApplicationContext(), Uri.parse(myvidou_uri.toString()));
mediaPlayer1=MediaPlayer.create(getApplicationContext(),myvidou_uri);
mediaPlayer1.setDisplay(holder);
textView1.setText("info\n");

Related

How to use JavaFX in Main

I am completly lost atm. I have been working with scenebuilder and javaFX in the past but I am stuck like 5 hours now and I didnt get a step further. Let me explain:
I have a working java Eclipse Project, using maven dependencies
The Main is where I want to use JavaFX or load a fxml into
The programm takes many many VCC Files and extracts the data to put it all together in an excel
The programm works but I cant load a FXML file into the main or even show a pane in there
Now does my Java Main class has to extend Application? I tried both ways - doenst work.
Some example code:
public void start(Stage primaryStage) {
try {
bpmain = new BorderPane(FXMLLoader.load(new File("src\\fxml\\UserInterface.fxml").toURI().toURL()));
primaryStage.setScene(new Scene(bpmain));
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
or this (from original Docs)
public void start(Stage stage) {
Circle circ = new Circle(40, 40, 30);
Group root = new Group(circ);
Scene scene = new Scene(root, 400, 300);
stage.setTitle("My JavaFX Application");
stage.setScene(scene);
stage.show();
}
but this start method is just not getting called... where do I put that?
What my Programm should look like is pretty simple actually. I want a small UI Windows that lets you pick a Folder where the VCC data lives in and a OK Button that basically should run the Main method.
So a TextField that when its picked a Path in the Main gets replaced (filepath) and just a simple OK Button that says: yeah run the main - because the main works perfectly it is just that I cant show that ui and I dont know how to really connect it to the Main.java
Any help is appreciated - Ty
Option 1
public class Launch extends Application {
public static Stage stage = null;
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/fxml/Main.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
this.stage = stage;
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Option 2:
public class SidebarController implements Initializable {
#Override
public void initialize(URL url, ResourceBundle rb) {
}
#FXML
void btnHome_OnMouseClicked(MouseEvent event) throws IOException {
BorderPane borderPane = (BorderPane) ((Node) event.getSource()).getScene().getRoot();
Parent sidebar = FXMLLoader.load(getClass().getResource("/fxml/ContentArea.fxml"));
borderPane.setCenter(sidebar);
}
}

java.lang.IllegalStateException: Application launch must not be called more than once - JavaFX (first once works, the 2nd non-) [duplicate]

How to call the launch() more than once in java i am given an exception as "ERROR IN MAIN:java.lang.IllegalStateException: Application launch must not be called more than once"
I have create rest cleint in my java application when request comes it call javafx and opening webview after completing webview operarion am closing javafx windows using Platform.exit() method. when second request comes am getting this error how to reslove this error.
JavaFx Application Code:
public class AppWebview extends Application {
public static Stage stage;
#Override
public void start(Stage _stage) throws Exception {
stage = _stage;
StackPane root = new StackPane();
WebView view = new WebView();
WebEngine engine = view.getEngine();
engine.load(PaymentServerRestAPI.BROWSER_URL);
root.getChildren().add(view);
engine.setJavaScriptEnabled(true);
Scene scene = new Scene(root, 800, 600);
stage.setScene(scene);
engine.setOnResized(new EventHandler<WebEvent<Rectangle2D>>() {
public void handle(WebEvent<Rectangle2D> ev) {
Rectangle2D r = ev.getData();
stage.setWidth(r.getWidth());
stage.setHeight(r.getHeight());
}
});
JSObject window = (JSObject) engine.executeScript("window");
window.setMember("app", new BrowserApp());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
RestClient Method:
Calling to JavaFX application
// method 1 to lanch javafx
javafx.application.Application.launch(AppWebview.class);
// method 2 to lanch javafx
String[] arguments = new String[] {"123"};
AppWebview .main(arguments);
You can't call launch() on a JavaFX application more than once, it's not allowed.
From the javadoc:
It must not be called more than once or an exception will be thrown.
Suggestion for showing a window periodically
Just call Application.launch() once.
Keep the JavaFX runtime running in the background using Platform.setImplicitExit(false), so that JavaFX does not shutdown automatically when you hide the last application window.
The next time you need another window, wrap the window show() call in Platform.runLater(), so that the call gets executed on the JavaFX application thread.
For a short summary implementation of this approach:
See the answer by sergioFC
If you are mixing Swing you can use a JFXPanel instead of an Application, but the usage pattern will be similar to that outlined above.
For an example of the JFXPanel apprach, see Irshad Babar
s answer.
Wumpus Sample
This example is bit more complicated than it needs to be because it also involves timer tasks. However it does provide a complete stand-alone example, which might help sometimes.
import javafx.animation.PauseTransition;
import javafx.application.*;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.*;
// hunt the Wumpus....
public class Wumpus extends Application {
private static final Insets SAFETY_ZONE = new Insets(10);
private Label cowerInFear = new Label();
private Stage mainStage;
#Override
public void start(final Stage stage) {
// wumpus rulez
mainStage = stage;
mainStage.setAlwaysOnTop(true);
// the wumpus doesn't leave when the last stage is hidden.
Platform.setImplicitExit(false);
// the savage Wumpus will attack
// in the background when we least expect
// (at regular intervals ;-).
Timer timer = new Timer();
timer.schedule(new WumpusAttack(), 0, 5_000);
// every time we cower in fear
// from the last savage attack
// the wumpus will hide two seconds later.
cowerInFear.setPadding(SAFETY_ZONE);
cowerInFear.textProperty().addListener((observable, oldValue, newValue) -> {
PauseTransition pause = new PauseTransition(
Duration.seconds(2)
);
pause.setOnFinished(event -> stage.hide());
pause.play();
});
// when we just can't take it anymore,
// a simple click will quiet the Wumpus,
// but you have to be quick...
cowerInFear.setOnMouseClicked(event -> {
timer.cancel();
Platform.exit();
});
stage.setScene(new Scene(cowerInFear));
}
// it's so scary...
public class WumpusAttack extends TimerTask {
private String[] attacks = {
"hugs you",
"reads you a bedtime story",
"sings you a lullaby",
"puts you to sleep"
};
// the restaurant at the end of the universe.
private Random random = new Random(42);
#Override
public void run() {
// use runlater when we mess with the scene graph,
// so we don't cross the streams, as that would be bad.
Platform.runLater(() -> {
cowerInFear.setText("The Wumpus " + nextAttack() + "!");
mainStage.sizeToScene();
mainStage.show();
});
}
private String nextAttack() {
return attacks[random.nextInt(attacks.length)];
}
}
public static void main(String[] args) {
launch(args);
}
}
Update, Jan 2020
Java 9 added a new feature called Platform.startup(), which you can use to trigger startup of the JavaFX runtime without defining a class derived from Application and calling launch() on it. Platform.startup() has similar restrictions to the launch() method (you cannot call Platform.startup() more than once), so the elements of how it can be applied is similar to the launch() discussion and Wumpus example in this answer.
For a demonstration on how Platform.startup() can be used, see Fabian's answer to How to achieve JavaFX and non-JavaFX interaction?
I use something like this, similar to other answers.
private static volatile boolean javaFxLaunched = false;
public static void myLaunch(Class<? extends Application> applicationClass) {
if (!javaFxLaunched) { // First time
Platform.setImplicitExit(false);
new Thread(()->Application.launch(applicationClass)).start();
javaFxLaunched = true;
} else { // Next times
Platform.runLater(()->{
try {
Application application = applicationClass.newInstance();
Stage primaryStage = new Stage();
application.start(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
try this, I tried this and found successful
#Override
public void start() {
super.start();
try {
// Because we need to init the JavaFX toolkit - which usually Application.launch does
// I'm not sure if this way of launching has any effect on anything
new JFXPanel();
Platform.runLater(new Runnable() {
#Override
public void run() {
// Your class that extends Application
new ArtisanArmourerInterface().start(new Stage());
}
});
} catch (Exception e) {
e.printStackTrace();
}
}

JavaFX8 MediaPlayer no sound error/wrong URL

I'm working on JavaFX 8 app and I'm trying to open MP3 file using MediaPlayer.
I had passed wrong URL errors and I've no exceptions right now, when I start such part of code, but app opens and there is no sound. Tried with some oracle tutorial and when i put such URL: "http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv" everything is working so I guess it's still wrong URL, but app is starting and I've litterally no clue whats wrong.
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
//Add a scene
Group root = new Group();
Scene scene = new Scene(root, 500, 200);
File file = new File("C:\\Users\\Me\\Desktop\\SomeFile.mp3");
Media media = new Media(file.toURI().toASCIIString());
MediaPlayer mediaPlayer = new MediaPlayer(media);
mediaPlayer.setAutoPlay(true);
// create mediaView and add media player to the viewer
MediaView mediaView = new MediaView(mediaPlayer);
((Group)scene.getRoot()).getChildren().add(mediaView);
//show the stage
primaryStage.setTitle("Media Player");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Considering the file is correctly located and loaded you can do the following:
file.toURI().toURL().toExternalForm()
If you are writing an app that plays various media files, consider using user interface to obtain paths to external file resources instead of hardcoding them. You can use FileChooser or DirectoryChooser

Create a native bundle for a JavaFX application that has a preloader

I have a JavaFX application that uses a preloader. What I'd like to do is package it up as a native bundle (Mac app or Windows exe file that contains a copy of the Java JDK) so users who don't have the right version of Java on their computers can still run the app. I've followed Oracles instructions for creating native bundles and for adding preloaders. What I get is exactly what you'd expect—a native bundle that runs my program.
The problem is that the bundle completely ignores my preloader. It just runs the main program (after a long load time). I know the preloader is included because, when I run the jar file alone, it shows up.
Has anyone successfully bundled a JavaFX app with a preloader? Can you guide me through how to do so? I'm using Netbeans.
EDIT:
Here is the Preloader:
import javafx.application.Preloader;
import javafx.application.Preloader.ProgressNotification;
import javafx.application.Preloader.StateChangeNotification;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Splash extends Preloader {
ProgressIndicator bar;
ImageView Background;
Stage stage;
private Scene createPreloaderScene() {
bar = new ProgressIndicator();
bar.setLayoutX(380);
bar.setLayoutY(250);
bar.setPrefSize(60, 60);
Background = new ImageView("Images/Splash.png");
Background.setEffect(null);
Pane p = new Pane();
p.setStyle("-fx-background-color: transparent;");
p.getChildren().addAll(Background, bar);
Scene scene = new Scene(p, 794, 587);
scene.setFill(null);
scene.getStylesheets().add(Scrap2.class.getResource("CSS/Progress.css").toExternalForm());
bar.setId("myprogress");
return scene;
}
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
stage.setScene(createPreloaderScene());
stage.initStyle(StageStyle.TRANSPARENT);
stage.show();
}
#Override
public void handleStateChangeNotification(StateChangeNotification scn) {
if (scn.getType() == StateChangeNotification.Type.BEFORE_START) {
stage.hide();
}
}
#Override
public void handleProgressNotification(ProgressNotification pn) {
bar.setProgress(pn.getProgress());
}
#Override
public void handleApplicationNotification(PreloaderNotification arg0) {
if (arg0 instanceof ProgressNotification) {
ProgressNotification pn= (ProgressNotification) arg0;
bar.setProgress(pn.getProgress());
}
}
}
And here is the first part of my main program:
#Override
public void init(){
/*Root*/
root = new Pane();
root.setStyle("-fx-background-color: transparent;");
root.setLayoutX(150);
notifyPreloader(new Preloader.ProgressNotification(0.1));
/*Create Background*/
createBinding(stage);
createContents();
createSaveMessages();
createFlipBook();
notifyPreloader(new Preloader.ProgressNotification(0.2));
/*Add Pages*/
createOverview();
createAccounts();
notifyPreloader(new Preloader.ProgressNotification(0.3));
createCounselors();
createInsurance();
notifyPreloader(new Preloader.ProgressNotification(0.4));
createAssets();
createPapers();
notifyPreloader(new Preloader.ProgressNotification(0.5));
createLoans();
createFuneral();
notifyPreloader(new Preloader.ProgressNotification(0.6));
createWills();
addAllPages();
notifyPreloader(new Preloader.ProgressNotification(0.7));
/*Add Toolbar on top*/
createToolBar();
notifyPreloader(new Preloader.ProgressNotification(0.9));
/*Create Opening Instructions*/
opening();
/*Load Saved Data*/
load();
notifyPreloader(new Preloader.ProgressNotification(1.0));
}
#Override
public void start(Stage stage) {
/*Scene*/
scene = new Scene(root, 1200, 700);
stage.setScene(scene);
scene.setFill(null);
/*Stage*/
this.stage = stage;
stage.initStyle(StageStyle.TRANSPARENT);
stage.centerOnScreen();
stage.show();
}
This example will work with installers exe/msi/image only (have no Mac to test dmg). This step by step assumes, that you already installed the needed tools like InnoSetup, Wix Toolset, etc. It also assumes, that you have configured the tools to run with netbeans (setting paths, edit config files, etc.).
Prerequirements:
Inno Setup for .exe package, download the unicode version: http://www.jrsoftware.org/isdl.php
Wix Toolset for .msi package: http://wixtoolset.org/
Set Windows Paths for Inno Setup and Wix Toolset
Step 1:
I've made a new JavaFX Application Project in Netbeans like this:
Step 2:
Then I gave the project a name and said, that the wizard should create a preloader project with the given name too. Additionally it should create an application class in given package name.
Step 3:
After that I right clicked on the application project and select under deployment "Enable Native Packaging".
Step 4:
In step 4 I've created the code for the application. The preloader will be updated in the init() method and only there. All your work for initialization the application should go here.
JavaFXPreloaderApp.java
import javafx.application.Application;
import javafx.application.Preloader;
import javafx.event.ActionEvent;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class JavaFXPreloaderApp extends Application {
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(createContent(), 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public Parent createContent() {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction((ActionEvent event) -> {
System.out.println("Hello World!");
});
StackPane root = new StackPane();
root.getChildren().add(btn);
return root;
}
#Override
public void init() throws Exception {
// A time consuming task simulation
final int max = 10;
for (int i = 1; i <= max; i++) {
notifyPreloader(new Preloader.ProgressNotification(((double) i) / max));
Thread.sleep(500);
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Step 5:
The only missing part was the preloader code. Look for the only needed method handleApplicationNotification, all the other methods, like handleProgressNotification or handleStateChangeNotification, you can safely delete, or make them empty stubs.
JavaFXPreloader.java
import javafx.application.Preloader;
import javafx.application.Preloader.ProgressNotification;
import javafx.application.Preloader.StateChangeNotification;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
/**
* Simple Preloader Using the ProgressBar Control
*/
public class JavaFXPreloader extends Preloader {
ProgressBar bar;
Stage stage;
private Scene createPreloaderScene() {
bar = new ProgressBar();
BorderPane p = new BorderPane();
p.setCenter(bar);
return new Scene(p, 300, 150);
}
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
stage.setScene(createPreloaderScene());
stage.show();
}
#Override
public void handleApplicationNotification(PreloaderNotification info) {
// Check if info is ProgressNotification
if (info instanceof ProgressNotification) {
// if yes, get the info and cast it
ProgressNotification pn = (ProgressNotification) info;
// update progress
bar.setProgress(pn.getProgress());
// if this was the last progress (progress reached 1), hide preloader
// this is really important, if preloader isn't hide until app loader
// reaches the start method of application and tries to open the stage of
// the main app with the show() method, it will not work.
if (pn.getProgress() == 1.0) {
stage.hide();
}
}
}
}
Step 6:
Now it was time to bundle the application to native packages (image only/exe/msi). I right clicked on the applicaton project and selected the packages to create one by one.
Step 7:
After choosen to package as image only your directory should look like this:
Step 8:
After digging deeper in your directory you should find the image:
Step 9:
A double click on the .exe file should start your application:
Remarks:
The biggest mistake you could do is, to call things in your application start methods. Normaly all have to be done in the application init method, there you load the huge files, there you will connect to the db, or there you load a huge custom layout with a lot of css or fxml files. And there is the place to say good bye to the preloader (progress = 1). Try not to do things at the preloader in your application start method. Don't think in Thread's, the preloader is there to do things before the main stage is shown, so load all in sequence.

Play audio file with JavaFX mediaplayer from another class

Media player class is good. However, I can't play a mp3 file stored in another class (when mouse clicked). Could someone check my code?
package mediaplayer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.media.Media;
import javafx.stage.Stage;
public class MediaPlayer extends Application {
private static final String MEDIA_URL = "http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv";
private static String arg1;
#Override public void start(Stage stage) {
stage.setTitle("Media Player");
Group root = new Group();
Scene scene = new Scene(root,600,265);
// create media player
Media media = new Media((arg1 != null) ? arg1 : MEDIA_URL);
javafx.scene.media.MediaPlayer mediaPlayer = new javafx.scene.media.MediaPlayer(media);
mediaPlayer.setAutoPlay(true);
MediaControl mediaControl = new MediaControl(mediaPlayer);
scene.setRoot(mediaControl);
scene.getStylesheets().add(MediaPlayer.class.getResource("mediaplayer.css").toExternalForm());
// show stage
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
if (args.length > 0) {
arg1 = args[0];
}
Application.launch(args);
}
}
This is the class I am trying to use to play my audio file:
package mediaplayer;
import java.awt.Cursor;
/**
*
* #author Yves
*/
public class LacherPrise extends javax.swing.JFrame {
/**
* Creates new form LacherPrise
*/
public LacherPrise() {
this.setVisible(true);
// définition de la taille de la fenêtre de l’éditeur
setBounds(200, 100, 800, 600);
initComponents();
}
When I run the program (on the mouseclicked below), I get these two errors:
Error no1: Exception in thread "AWT-EventQueue-0" java.lang.UnsupportedOperationException: Not yet implemented
Error no2:Exception in thread "Thread-3" java.lang.IllegalStateException: Toolkit not initialized
I would need help on how to implement Exception.
private void audio010MouseClicked(java.awt.event.MouseEvent evt) {
//getting URL to a sound file stored locally
String MEDIA_URL = "file:///C:/Users/Yves/Documents/NetBeansProjects/ExamenFinSessionJavaFX/src/RessourcesLacherPrise/Aff010.mp3";
Media media = new Media(MEDIA_URL.toString());
MediaPlayer MediaPlayer = new MediaPlayer();
MediaPlayer.play(MEDIA_URL);
}
The main problem i believe is that the JavaFX toolkit has not been initialized. Take a look at the following question:
JavaFX 2.1: Toolkit not initialized
Simply putting this at the start of your code could solve the problem:
new JFXPanel();

Categories

Resources