javafx media player video Ending not working - java

When Launching the app , directly an intro video kicks in,
I have 2 scenarios :
Watch Full intro , then automatically redirect to another page
Click Skip button to get instantly redirected to another page
both of these 2 scenarios are working flawlessly when I run the app from the IDE,
but when a package the app to jar format the first scenario never work ( see the code for more details )
the Class :
public class SplashScreenController implements Initializable {
#FXML
private HBox introView;
#FXML
private Label btSkipIntro;
MediaPlayer player;
#Override
public void initialize(URL location, ResourceBundle resources) {
// INTRO VIDEO PROCESS ------------------------
player = new MediaPlayer(new Media(getClass().getResource("/Images/SeffirIntro.mp4").toExternalForm()));
MediaView mediaView = new MediaView(player);
mediaView.setPreserveRatio(true);
mediaView.setSmooth(true);
introView.getChildren().add(mediaView);
System.out.println("Started");
player.play();
player.setOnEndOfMedia(() -> {
System.out.println("Ended");
try {
// Code to automatically redirect to another page
Entry.viewNavigator.openView("/Views/LanguageView.fxml");
} catch (IOException e) {
e.printStackTrace();
}
});
#FXML // When the skip button clicked
public void skipClicked() throws IOException{
System.out.println("Skipped");
player.stop();
Entry.viewNavigator.openView("/Views/LanguageView.fxml");
}
in my IDE testing the ( player.setOnEndOfMedia lambda function executes beautifly) but when the jar executes that function is never accessed.
The JAR creation was tested with both maven and the artifact build , both same result the function after when the video ends , doesn't fire
any explanation on why is this issue is happening will be of great help
thanx in advance

Related

(help still needed) How to make a playvideo function that returns when video is over?

So I am using JavaFX and want to set up an experiment where I have to play many videos and interact with the user. For this setup I would like to write a function that receives a filename and plays the video with that name. But it should only return when the video is over, and not before. So something like this:
private void play(URI name){
MediaPlayer mediaPlayer = new MediaPlayer(new Media(name));
mediaPlayer.setAutoPlay(true);
view.setMediaPlayer(mediaPlayer);
}
However this function returns before the video is over, making the execution of the program a complete mess. I know MediaPlayer has a setOnEndOfMedia(Runnable) function but I am not sure how I could potentially use that to achieve my goal.
This is the code I have at the moment. But it does not work. The problem being that both videos are played at the same time, likely because the play function returns as soon as it has started the video. I have also tried just adding a while(true) loop at the end of the play function so that it gets stuck there until the return; in .setOnEndOfMedia is callled, that prevented any video's from being played at all.
CODE:
static MediaView view;
#Override
public void start(Stage stage) throws IOException, URISyntaxException, InterruptedException {
// Create full screen scene
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
stage.setFullScreen(true);
Scene scene = new Scene(new Group(), dim.getWidth(), dim.getHeight());
stage.setScene(scene);
stage.show();
// Create the view and add it to the Scene.
view = new MediaView();
((Group)scene.getRoot()).getChildren().add(view);
play("videol");
play("video2");
}
private static void play(String name) throws InterruptedException {
Media media = new Media(uri(name));
MediaPlayer player = new MediaPlayer(media);
player.setOnReady(() -> {
player.play();
player.setOnEndOfMedia(() -> {
player.dispose();
return;
});
});
view.setMediaPlayer(player);
}
private static String uri(String name) {
return Paths.get("clips/" + name + ".mp4").toUri().toString();
}
public static void main(String[] args) {
launch(args);
}
Keeping my original stuff since it is useful for others.
Anyways the problem with your code is that you are calling the method twice, right after itself. You need to call the method from within the EndOfMedia part. If you wish you can create a list and for the parameter when using recursion you can use list.poll() to take and remove the first string in the list. Then when the list is null you can just return to the interface. Just some ideas.
What I would suggest you use is to create a method for playing your music which takes a String as a parameter, this string would be then used to find its equivalent in a hashmap, say HashMap<String, MediaPlayer>. Then to the part where you actually need help. I suggest you write something like this:
mediaPlayer.setOnReady(() -> {
mediaPlayer.play();
mediaPlayer.setOnEndOfMedia(() -> {
mediaPlayer.dispose();
MusicPlayer();
});
});
Basically, you are playing the media when ready and then at the end disposing of it and calling the method again and in where my code uses recursion and calls the method MusicPlayer you can instead 'return'. Sorry if this is poorly explained, if you need further help just comment below.

Progress indicator remains indeterminate and there is no download

I have written a piece of code for downloading a file from internet (in background service) and showing the progress of download in a popup stage. The code compiles successfully and there is no runtime error. However no download takes place and progress indicator remains indeterminate.
The code is tailored for illustrating my point. Please have a look at it and let me understand where I have gone wrong.
Thanks!
public class ExampleService extends Application {
URL url;
Stage stage;
public void start(Stage stage)
{
this.stage = stage;
stage.setTitle("Hello World!");
stage.setScene(new Scene(new StackPane(addButton()), 400, 200));
stage.show();
}
private Button addButton()
{
Button downloadButton = new Button("Download");
downloadButton.setOnAction(new EventHandler<ActionEvent>()
{
public void handle(ActionEvent e)
{
FileChooser fileSaver = new FileChooser();
fileSaver.getExtensionFilters().add(new FileChooser.ExtensionFilter("PDF", "pdf"));
File file = fileSaver.showSaveDialog(stage);
getDownloadService(file).start();
}
});
return downloadButton;
}
private Service getDownloadService(File file)
{
Service downloadService = new Service()
{
protected Task createTask()
{
return doDownload(file);
}
};
return downloadService;
}
private Task doDownload(File file)
{
Task downloadTask = new Task<Void>()
{
protected Void call() throws Exception
{
url = new URL("http://www.daoudisamir.com/references/vs_ebooks/html5_css3.pdf");
// I have used this url for this context only
org.apache.commons.io.FileUtils.copyURLToFile(url, file);
return null;
}
};
showPopup(downloadTask);
return downloadTask;
}
Popup showPopup(Task downloadTask)
{
ProgressIndicator progressIndicator = new ProgressIndicator();
progressIndicator.progressProperty().bind(downloadTask.progressProperty());
Popup progressPop = new Popup();
progressPop.getContent().add(progressIndicator);
progressPop.show(stage);
return progressPop;
// I have left out function to remove popup for simplicity
}
public static void main(String[] args)
{
launch(args);
}}
The line:
org.apache.commons.io.FileUtils.copyURLToFile(url, file);
...doesn't provide you any information about the progress of your download (there is no callback or any other indication of its progress). It just downloads something without giving you feedback.
You will have to use something else that gives you feedback on the progress.
Take a look at this questions answers for solutions with feedback (it is for Swing, but you should be able to adapt them for JavaFX): Java getting download progress
You bind the ProgressIndicator's progress property to the Task's progress property, so that changes in the latter will be reflected in the former. However you never actually update your Task's progress.
If you want the progress indicator to show something, you're going to have to call updateProgress(workDone, max) within your task's body (or elsewhere). And that might be tricky if the download logic you're using doesn't give you any progress callbacks. (You could, perhaps, spawn a thread to repeatedly check the size of the file on the filesystem and use that as your current workDone; but you'd need to know what the eventual/complete size of the file would be in order to turn this into a percentage, which may or may not be easy.)

Load FXML in initialize()

I'm creating my first JavaFX application, and I'm doing OK so far. I'm just encountering one problem.
For displaying and loading FXML files I'm using a VistaNavigator class found on StackOverflow:
public static void loadVista(String fxml) {
try {
mainController.setVista(
FXMLLoader.load(
VistaNavigator.class.getResource(
fxml
)
)
);
} catch (IOException e) {
e.printStackTrace();
}
}
I have a ScanController, which receives input from the keyboard and checks a ticket ID based on this input. When the ticket is OK, it loads "scan-success.fxml", otherwise it loads "scan-failure.xml", each of these FXML-files have an own controller. I'm loading the success FXML like this:
VistaNavigator.loadVista(VistaNavigator.VISTA_SCAN_SUCCESS);
This is working great. The Success-FXML page is showing and the ScanSuccessController is loading. In the initialize() method of ScanSuccessController.java I have the following code snippet:
try {
Thread.sleep(2000); //1000 milliseconds is one second.
VistaNavigator.loadVista(VistaNavigator.VISTA_SCAN_HOME);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
So I would like to show the success-page for about 2 seconds, and then head back to the home screen (scan-home.fxml with controller ScanHomeController.java) to scan some more tickets. However, when executing this code, just 'nothing' happens, no exception and no change of FXML-file.
When I try to load a new vista after clicking a button (in an EventHandler) it works great.
I can imagine that JavaFX is not able to load a new FXML-file before the controller has been fully initialised, but cannot figure out where to put this line of code..
I hope someone can help me out with this.
What about this:
#Override
public void initialize(URL url, ResourceBundle rb) {
Timeline timeline=new Timeline();
timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(2),
e->VistaNavigator.loadVista(VistaNavigator.VISTA_SCAN_HOME)));
timeline.play();
}
Note that by using a Timeline everything runs in the JavaFX thread.

What is best way to pass object in JavaFX scene

(note, what i newbie in java)
I a little bit stuck in solving the problem of pass object between javafx scenes and classes.
For example, i have class, which waits for data by server; main class and 2 javafx windows.
Let it looks like this:
Listener.java.
Let it work at another thread. When we got "nelo" from server, then it'll means, what user not logged it, and then, we should open Login Window
// some package
// some imports
public class Listener extends Thread {
public void run() {
System.out.println("[INF] Wait for server...");
while(true) {
handle();
}
}
public void handle()
{
try {
byte[] token = new byte[6];
DataInputStream src = new DataInputStream(in);
src.read(token);
String token_val = new String(token);
switch (token_val) {
case "_nelo_":
System.out.println("[INF] Auth required");
break;
}
} catch (IOException e) {
}
}
}
Okay, there nothing weird. Just simple class for listening.
But here my troubles started. I try to explain it. (previosly, Sorry for bad english, i still learn this language)
Lets create login window (imagine that fxml file and controller created :) ):
// some package
// some imports
public class WindowLogin extends Application{
private Stage stage;
#Override
public void start(Stage primaryStage) throws Exception {
stage = new Stage();
try {
URL location = getClass().getResource("../views/WindowLogin.fxml");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(location);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
Parent root = (Parent) fxmlLoader.load(location.openStream());
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void show(){
launch();
}
}
So, when user open application, client will try connect to server.
If connection success, then server ask client for auth (Show login window). Next - user enter login and pass and click "Login" button. (Login Window show some indication of proccess). If auth success - Hide login, else - show some info in window.
As a result, i need access from Listener to Login window Controller. i.e. as i wrote before - different answer from server - different elements displayed.
How i can realize access to LoginWindowController ?
Thanks in advance
I will give you basic guidance for each task:
Connection
If connection with the server is successful then:
Platform.runLater(new Runnable() {
public void run() {
try {
WindowLogin login = new WindowLogin();
login.start(new Stage());
} catch (Exception e) {
e.printStackTrace();
}
}
});
Login
Error
You set a blank label on the WindowController and if the user cound't autheticate, than you fill this label.
Succesful login
You could use the same Platform.runLater as I used it before, or you could do something using stackpane and changing it's order ( I strongly recommend to use the Platform.runLater).

How to create background service in JavaFX

I've been away from Java for some years and have started to pick it up again a couple of days ago. I'll need to create a GUI using FXML and to get some practice I'm implementing a little chat application as an exercise.
I want to create a background thread which listens on a port and sends received messages to a textArea. By what I've read, this is best done by using the 'javafx.concurrent' package.
So I came up with the following:
import javafx.concurrent.Service;
import javafx.concurrent.Task;
public class ListenOnPort extends Service<Void> {
#Override protected Task<Void> createTask() {
return new Task<Void>() {
#Override protected Void call() throws Exception {
updateMessage("Bla!");
/*
int max = 50;
for (int i = 1; i <= max; i++) {
updateProgress(i, max);
updateMessage(String.valueOf(i));
Thread.sleep(50);
}
*/
return null;
} //call()
};
} //createTask()
}// ListenOnPort
The [shortened] controller is:
public class FXMLDocumentController {
#FXML private Label status;
#FXML private ProgressBar progressBar;
ListenOnPort listenService;
#FXML void startListening(ActionEvent event) {
localPort = Integer.parseInt(listenPort.getText());
status.setText("Attempting to open local port " +localPort +" for listening.");
listenService.start();
}
#FXML void initialize() {
// assertions
listenService = new ListenOnPort();
/*>>>*/ progressBar.progressProperty().bind(listenService.progressProperty());
status.textProperty().bind(listenService.messageProperty());
}
}
Which results in:
java.lang.NullPointerException
at p2pchat.FXMLDocumentController.initialize(FXMLDocumentController.java:130)
Line 130 is the second to last line of code, marked with '/>>>/'.
Why do I get a nullPointerException? What am i doing wrong?
First, make sure you created a ProgressBar element in the .fxml file with an fx:id of progressBar.
Then in your IDE click in your project folder and press F5, it will refresh the .fxml and it will see the most updated version. Otherwise the IDE will not see the recent modifications you've made to your .fxml file and will cause the NullPointerException.

Categories

Resources