Search code examples
javajavafxnetbeansmedia-player

Video Player JavaFx


I am building a Video Player using JavaFx in Netbeans IDE. I need to set the label shown in the screen builder below to display the total duration of the video.

When I use System.out.println(""+mediaPlayer.getDuration.toSeconds()); I get the result in output form. However, when I use label.setText(""+mediaPlayer.getDuration.toSeconds()); I get a NullPointerException.

How can I display the total duration of the video in the label?

My FXMLDocumentController.java code

public class FXMLDocumentController implements Initializable {

private MediaPlayer mediaPlayer; 
private String filePath;

@FXML
private Label label;

@FXML
private Slider seek;

@FXML
private Slider volume;

@FXML
private MediaView mediaView;

@FXML
private void handleButtonAction(ActionEvent event) throws InterruptedException {



    FileChooser fileChooser = new FileChooser();
    FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter("Select File (*.mp4)", "*.mp4");
        fileChooser.getExtensionFilters().add(filter);
        File file = fileChooser.showOpenDialog(null);
        filePath = file.toURI().toString();

        if(filePath!=null)
        {
            Media media = new Media(filePath);
            mediaPlayer = new MediaPlayer(media);


            mediaView.setMediaPlayer(mediaPlayer);

                DoubleProperty width = mediaView.fitWidthProperty();
                DoubleProperty height = mediaView.fitHeightProperty();

                width.bind(Bindings.selectDouble(mediaView.sceneProperty(), "width"));
                height.bind(Bindings.selectDouble(mediaView.sceneProperty(),"height"));

                volume.setValue(mediaPlayer.getVolume() * 100);
                volume.valueProperty().addListener(new InvalidationListener() {
                @Override
                public void invalidated(Observable observable) {
                   mediaPlayer.setVolume(volume.getValue() / 100);
                }
            });

                mediaPlayer.currentTimeProperty().addListener(new ChangeListener<Duration>() {
                @Override
                public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) {
                    seek.setValue(newValue.toSeconds());
                }
            });

                seek.setOnMouseClicked(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent event) {
                    mediaPlayer.seek(Duration.seconds(seek.getValue()));
                }
            });
            mediaPlayer.setOnReady(new Runnable() {

            @Override
            public void run() 
                    {

                        label.setText("Duration: "+media.getDuration().toSeconds());
                       //Using Output -  System.out.println(""+mediaPlayer.getDuration.toSeconds());

                    }

                });
            mediaPlayer.play();
        }
}

@FXML
private void playVideo(ActionEvent event)
{
    mediaPlayer.play();
    mediaPlayer.setRate(1);
}

@FXML
private void pauseVideo(ActionEvent event)
{
    mediaPlayer.pause();
}

@FXML
private void stopVideo(ActionEvent event)
{
    mediaPlayer.stop();
}

@FXML
private void fastVideo(ActionEvent event)
{
    mediaPlayer.setRate(1.5);
}

@FXML
private void fasterVideo(ActionEvent event)
{
    mediaPlayer.setRate(2);
}

@FXML
private void slowVideo(ActionEvent event)
{
    mediaPlayer.setRate(0.75);
}

@FXML
private void slowerVideo(ActionEvent event)
{
    mediaPlayer.setRate(0.5);
}

@FXML
private void exitVideo(ActionEvent event)
{
     System.exit(0);
}

@Override
public void initialize(URL url, ResourceBundle rb) {
    // TODO
}    
}

My FXMLDocument.fxml code

 <?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.media.MediaView?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" stylesheets="@style.css" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="bideo.player.FXMLDocumentController">
   <bottom>
      <VBox alignment="CENTER" prefHeight="40.0" prefWidth="600.0" BorderPane.alignment="CENTER">
         <children>
            <HBox alignment="CENTER" prefHeight="40.0">
               <children>
                  <Button fx:id="openFile" minHeight="32.0" minWidth="32.0" mnemonicParsing="false" onAction="#handleButtonAction">
                     <HBox.margin>
                        <Insets left="10.0" />
                     </HBox.margin></Button>
                  <Button fx:id="playButton" minHeight="32.0" minWidth="32.0" mnemonicParsing="false" onAction="#playVideo">
                     <HBox.margin>
                        <Insets left="30.0" />
                     </HBox.margin></Button>
                  <Button fx:id="pauseButton" minHeight="32.0" minWidth="32.0" mnemonicParsing="false" onAction="#pauseVideo">
                     <HBox.margin>
                        <Insets left="5.0" />
                     </HBox.margin></Button>
                  <Button fx:id="stopButton" minHeight="32.0" minWidth="32.0" mnemonicParsing="false" onAction="#stopVideo">
                     <HBox.margin>
                        <Insets left="5.0" />
                     </HBox.margin></Button>
                  <Button fx:id="slowerButton" mnemonicParsing="false" onAction="#slowerVideo" text="&lt;&lt;&lt;">
                     <HBox.margin>
                        <Insets left="30.0" />
                     </HBox.margin></Button>
                  <Button fx:id="slowButton" mnemonicParsing="false" onAction="#slowVideo" text="&lt;&lt;" />
                  <Button fx:id="fastButton" mnemonicParsing="false" onAction="#fastVideo" text="&gt;&gt;" />
                  <Button fx:id="fasterButton" mnemonicParsing="false" onAction="#fasterVideo" text="&gt;&gt;&gt;" />
                  <Button mnemonicParsing="false" onAction="#exitVideo" text="Exit" />
                  <Slider fx:id="volume" prefHeight="14.0" prefWidth="72.0">
                     <HBox.margin>
                        <Insets left="20.0" />
                     </HBox.margin>
                  </Slider>
                  <Label text="Label">
                     <HBox.margin>
                        <Insets left="15.0" />
                     </HBox.margin>
                  </Label>
               </children>
            </HBox>
         </children>
      </VBox>
   </bottom>
   <center>
      <StackPane prefHeight="150.0" prefWidth="200.0">
         <children>
            <MediaView fx:id="mediaView" fitHeight="200.0" fitWidth="200.0" StackPane.alignment="CENTER" />
            <Slider fx:id="seek" StackPane.alignment="BOTTOM_CENTER" />
         </children>
      </StackPane>
   </center>
</BorderPane>

Any help would be appreciated. Thanks.


Solution

  • I only spotted one Label element in you FXML document and it does not have a fx:id attribute. This means it is never injected into your controller.

    Based on your controller class, add fx:id="label" as an attribute to the <Label text="Label"> element.

    For future reference, since the major difference between the two lines of code was the use of the label field it is a good bet that the label field was the issue. And since it was a NullPointerException regarding a FXML injected field it is a good bet that the field was not injected due to the FXML document and controller class not being configured/coded correctly.

    It's the simple things that can really sneak up on ya.