2016-03-01 59 views
0

我是Java和JavaFX的新手 - 我正在制作一个小型播放器应用程序,并且发现持续时间计时器显示在标签上是一项挑战在我的显示器上。获取监听器类来更改控制器中Label的值

我最近尝试创建一个TimeListener.java类将改变持续时间值播放的每一个新的歌曲,并将它们设置在另一个类的标签上,但作为我碰到一个非静态误差来到这个想法是有缺陷的。

TrackPlayer对象类

private MediaPlayer player; 
    private Media track; 
    private String filepath; 

    private Duration duration; 

    public TrackPlayer(String filepath) { 
     this.filepath = filepath; 
     track = new Media(filepath); 
     player = new MediaPlayer(track); 

     player.setOnReady(() -> { 
      duration = track.getDuration(); 
      System.out.println("Duration: " + duration); 
     }); 

     player.currentTimeProperty().addListener(new TimeListener()); 
    } 

TimeListener类

public class TimeListener implements ChangeListener<Duration> { 

    @Override 
    public void changed(ObservableValue<? extends Duration> observable, Duration oldValue, Duration newValue) { 
     TrackPlayerController.setTime(newValue.toString()); 
    } 
} 

FXML Controller类

@FXML 
    private Label runTime; 

    ... 

    public void setTime(String time) { 
     //runTime.setText(time); 
    } 

我还能怎么解决这个问题?我想要一个标签,它会显示00:00:00(已过去)/ 00:00:00(持续时间)之类的东西,但我确定如果我只是获得持续工作时间,我也可以获得工作时间。

例同样的问题,但大多数,如果不是所有的功能删除

TrackPlayer类

package logic; 

import javafx.beans.property.ReadOnlyObjectProperty; 
import javafx.scene.media.Media; 
import javafx.scene.media.MediaPlayer; 
import javafx.scene.media.MediaPlayer.Status; 
import javafx.util.Duration; 

public class TrackPlayer { 

    private MediaPlayer player; 
    private Media track; 
    private String filepath; 

    private Duration duration; 

    public TrackPlayer(String filepath) { 
     this.filepath = filepath; 
     track = new Media(filepath); 
     player = new MediaPlayer(track); 

     player.setOnReady(() -> { 
      duration = track.getDuration(); 
      System.out.println("Duration: " + duration); 
     }); 
    } 

    public void playSong() { 
     System.out.println("Playing song"); 
     player.play(); 
    } 

    public void pauseSong() { 
     System.out.println("Pausing song"); 
     player.pause(); 
    } 

    public void stopSong() { 
     System.out.println("Stopping song"); 
     player.stop(); 
    } 

    public Status getStatus() { 
     return player.getStatus(); 
    } 

    public Duration getDuration() { 
     return duration; 
    } 

    public Duration getCurrentTime() { 
     return player.getCurrentTime(); 
    } 

    public Duration getStartTime() { 
     return player.getStartTime(); 
    } 

    public void setSeek(Duration duration) { 
     player.seek(duration); 
    } 

    public Media getMedia() { 
     return player.getMedia(); 
    } 

    public ReadOnlyObjectProperty<Duration> currentTimeProperty() { 
     return player.currentTimeProperty(); 
    } 

    public Duration getTotalDuration() { 
     return player.getTotalDuration(); 
    } 
} 

TrackPlayerController类

package gui; 

import java.io.IOException; 
import java.net.URL; 
import java.util.ResourceBundle; 
import javafx.event.ActionEvent; 
import javafx.fxml.FXML; 
import javafx.fxml.Initializable; 
import javafx.scene.control.Label; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableRow; 
import javafx.scene.control.TableView; 
import javafx.scene.control.cell.PropertyValueFactory; 
import logic.TrackPlayer; 
import logic.Track; 

public class TrackPlayerController implements Initializable { 

    @FXML 
    private TableView<Track> playingTable; 
    @FXML 
    private TableColumn<Track, String> playingTitleCol; 
    @FXML 
    private TableColumn<Track, String> playingArtistCol; 
    @FXML 
    private TableColumn<Track, String> playingGenreCol; 
    @FXML 
    private TableColumn<Track, String> playingRunTimeCol; 
    @FXML 
    private Label runTime; 

    private TrackPlayer player; 

    @Override 
    public void initialize(URL fxmlFileLocation, ResourceBundle resources) { 
     playingTitleCol.setCellValueFactory(new PropertyValueFactory<>("TrackTitle")); 
     playingArtistCol.setCellValueFactory(new PropertyValueFactory<>("TrackArtist")); 
     playingGenreCol.setCellValueFactory(new PropertyValueFactory<>("TrackGenre")); 
     playingRunTimeCol.setCellValueFactory(new PropertyValueFactory<>("RunTime")); 

     player.currentTimeProperty().addListener(observable -> { 
      setTime(player.getCurrentTime() 
        + "/" 
        + player.getTotalDuration()); 
     }); 

     playingTable.setRowFactory(tv -> { // Function for double-click to play (load) 
      TableRow<Track> row = new TableRow<>(); 
      row.setOnMouseClicked(event -> { 
       if (event.getClickCount() == 2 && (!row.isEmpty())) { 
        play(); 
       } 
      }); 
      return row; 
     }); 
    } 

    @FXML 
    private void play() { 
    } 

    @FXML 
    private void reset(ActionEvent e) { 
    } 

    @FXML 
    private void remove(ActionEvent e) { 
    } 

    @FXML 
    private void removeAll(ActionEvent e) { 
    } 

    @FXML 
    private void search(ActionEvent e) throws IOException { 
    } 

    public void setTime(String time) { 
     runTime.setText(time); 
    } 
} 

TrackPlayerMain类

package gui; 

import javafx.application.Application; 
import javafx.scene.Scene; 
import javafx.stage.Stage; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.layout.BorderPane; 

public class TrackPlayerMain extends Application { 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     BorderPane root = new BorderPane(); 

     FXMLLoader trackPlayerLoader = new FXMLLoader(getClass().getResource("TrackPlayer.fxml")); 
     root.setCenter(trackPlayerLoader.load()); 
     TrackPlayerController trackPlayerController = trackPlayerLoader.getController(); 

     Scene scene = new Scene(root, 600, 400); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 

} 

TrackPlayer FXML

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

<?import javafx.scene.paint.*?> 
<?import javafx.scene.text.*?> 
<?import java.lang.*?> 
<?import java.util.*?> 
<?import javafx.scene.*?> 
<?import javafx.scene.control.*?> 
<?import javafx.scene.layout.*?> 

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.TrackPlayerController"> 
    <children> 
     <Slider fx:id="timeSlider" layoutX="9.0" layoutY="333.0" prefHeight="25.0" prefWidth="582.0" /> 
     <Label alignment="BOTTOM_LEFT" layoutX="23.0" layoutY="10.0" prefHeight="17.0" prefWidth="75.0" text="Now Playing" /> 
     <Button fx:id="play" layoutX="250.0" layoutY="361.0" mnemonicParsing="false" onAction="#play" prefHeight="25.0" prefWidth="100.0" text="Play" /> 
     <Button fx:id="ff" layoutX="356.0" layoutY="361.0" mnemonicParsing="false" text="&gt;&gt;" /> 
     <Button fx:id="rw" layoutX="211.0" layoutY="361.0" mnemonicParsing="false" text="&lt;&lt;" /> 
     <Button fx:id="reset" layoutX="22.0" layoutY="361.0" mnemonicParsing="false" onAction="#reset" prefWidth="59.0" text="Reset" /> 
     <Button fx:id="remove" layoutX="498.0" layoutY="305.0" mnemonicParsing="false" onAction="#remove" prefWidth="83.0" text="Remove" /> 
     <Label fx:id="runTime" alignment="TOP_CENTER" layoutX="516.0" layoutY="350.0" prefHeight="17.0" prefWidth="75.0" text="00:00/00:00" textFill="#00000065"> 
     <font> 
      <Font size="11.0" /> 
     </font> 
     </Label> 
     <Button fx:id="removeAll" layoutX="401.0" layoutY="305.0" mnemonicParsing="false" onAction="#removeAll" prefHeight="25.0" prefWidth="83.0" text="Remove All" /> 
     <TableView fx:id="playingTable" layoutX="18.0" layoutY="32.0" prefHeight="263.0" prefWidth="563.0"> 
     <columns> 
      <TableColumn fx:id="playingTitleCol" editable="false" prefWidth="140.75" resizable="false" text="Title" /> 
      <TableColumn fx:id="playingArtistCol" editable="false" prefWidth="140.75" resizable="false" text="Artist" /> 
      <TableColumn fx:id="playingGenreCol" editable="false" prefWidth="140.75" resizable="false" text="Genre" /> 
      <TableColumn fx:id="playingRunTimeCol" prefWidth="140.75" resizable="false" text="Run Time" /> 
     </columns> 
     <columnResizePolicy> 
      <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> 
     </columnResizePolicy> 
     </TableView> 
     <Button fx:id="search" layoutX="303.0" layoutY="305.0" mnemonicParsing="false" onAction="#search" prefHeight="0.0" prefWidth="83.0" text="Search" /> 
    </children> 
</AnchorPane> 

从我假设它抛出NullPointerException异常,因为它试图initalize但是,随着选手对象尚未创建当前时间和持续时间的监听器(因为没有歌曲是从一开始就玩,只有当选择和按下播放) - 如果是这种情况如何添加监听器?

编辑:好的,所以我测试了导致NullPointerException的原因,它的播放器为空,因为程序启动时会执行此操作。

if (player != null) { 
    player.currentTimeProperty().addListener(observable -> { 
     runTime.setText(player.getCurrentTime() 
       + "/" 
       + player.getTotalDuration()); 
    }); 
} 

但是,当我这样做时,侦听器不会被初始化,因为runTime标签根本不会改变。这是我试图解决的问题。我怎样才能解决它?

回答

1

非FXML基于采样

下面是一些示例代码,它不使用FXML,但原理是一样的你是否有FXML参与与否。您只需将侦听器添加到相关属性中,并在更改时采取相应的操作。我没有按照您的问题格式化持续时间,但这与响应侦听器中的更改的问题相比是微不足道的。

sample

import javafx.application.Application; 
import javafx.scene.Scene; 
import javafx.scene.control.Label; 
import javafx.scene.layout.VBox; 
import javafx.scene.media.*; 
import javafx.stage.Stage; 

public class VideoPlayerExample extends Application { 
    private static final String MEDIA_LOC = 
      "http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv"; 

    @Override 
    public void start(final Stage stage) throws Exception { 
     final MediaPlayer oracleVid = new MediaPlayer(
       new Media(MEDIA_LOC) 
     ); 

     Label progress = new Label(); 
     oracleVid.currentTimeProperty().addListener(observable -> { 
      progress.setText(
        oracleVid.getCurrentTime() 
          + "/" 
          + oracleVid.getTotalDuration() 
      ); 
     }); 

     VBox layout = new VBox(10, progress, new MediaView(oracleVid)); 
     stage.setScene(new Scene(layout, 540, 208)); 
     stage.show(); 

     oracleVid.play(); 
    } 

    public static void main(String[] args) throws Exception { 
     launch(args); 
    } 
} 

我应该在哪里放置监听器?

如果没有看到完整的代码很难推荐,所以我只是做一些假设并提供建议以帮助您入门。所以,让我们假设:在

  1. 您正在定义和嵌入在FXML类似机制定制的媒体播放器控制概述:
  2. 持续时间跟踪标签(用于某些原因)不是自定义媒体控制的一部分。
  3. 因此,您的FXML包含两个组件,您的自定义媒体播放器和持续时间标签。

在这种情况下,收听者位于所述控制器用于包括媒体播放器和持续时间标签和initialize()呼叫该控制器过程中设置了包围FXML文件。

FXML基于采样

在一般情况下,这样的事情对通用再利用如前面概述您可以创建一个自定义的控制,但为了简便起见此示例将只使用内置MediaView和Label控件,而比自定义控件。

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

<?import javafx.scene.control.Label?> 
<?import javafx.scene.layout.VBox?> 
<?import javafx.scene.media.MediaView?> 
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" spacing="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="plot.VideoPlayerController"> 
    <children> 
     <Label fx:id="progress" text="Label" /> 
     <MediaView fx:id="mediaView" fitHeight="208.0" fitWidth="540.0" /> 
    </children> 
</VBox> 

应用

import javafx.application.Application; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Parent; 
import javafx.scene.Scene; 
import javafx.stage.Stage; 

public class VideoPlayerApp extends Application { 
    @Override 
    public void start(final Stage stage) throws Exception { 
     FXMLLoader loader = new FXMLLoader(getClass().getResource("player.fxml")); 
     Parent root = loader.load(); 

     stage.setScene(new Scene(root)); 
     stage.show(); 
    } 

    public static void main(String[] args) throws Exception { 
     launch(args); 
    } 
} 

控制器

import javafx.fxml.FXML; 
import javafx.scene.control.Label; 
import javafx.scene.media.Media; 
import javafx.scene.media.MediaPlayer; 
import javafx.scene.media.MediaView; 

public class VideoPlayerController {  
    private static final String MEDIA_LOC = 
      "http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv"; 

    @FXML 
    MediaView mediaView; 

    @FXML 
    Label progress; 

    public void initialize() { 
     final MediaPlayer oracleVid = new MediaPlayer(
       new Media(MEDIA_LOC) 
     ); 

     oracleVid.currentTimeProperty().addListener(observable -> { 
      progress.setText(
        oracleVid.getCurrentTime() 
          + "/" 
          + oracleVid.getTotalDuration() 
      ); 
     }); 

     mediaView.setMediaPlayer(oracleVid); 

     oracleVid.play(); 
    }  
} 
+0

我只是不明白了一两件事,我应该在哪里放置监听器?当你传递一个文件路径时,我有TrackPlayer类的函数,如play,stop和TrackPlayer对象本身,而控制器类则是我所有按钮的函数。 我一直在试图找到关于这些事情的标准布局的东西,但我没有成功。如果我把它放在我唯一的另一个监听器(在TrackPlayer的构造函数中),我会得到一个错误,说控制器类中的setTime不能从静态上下文中引用。 –

+1

我没有时间查看非现场资源,希望您在当前答案中有足够的信息,因为它可以帮助您确定正确的应用方法。对于将来的问题,您可能会考虑在问题中提供[mcve](http://stackoverflow.com/help/mcve),即可以复制和粘贴以便立即复制问题的完整的最小可编译代码。 – jewelsea

+0

我添加了生成相同问题的最小代码。我相信我明白为什么会出现这个问题,但我不知道如何去解决问题。 –