我是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=">>" />
<Button fx:id="rw" layoutX="211.0" layoutY="361.0" mnemonicParsing="false" text="<<" />
<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标签根本不会改变。这是我试图解决的问题。我怎样才能解决它?
我只是不明白了一两件事,我应该在哪里放置监听器?当你传递一个文件路径时,我有TrackPlayer类的函数,如play,stop和TrackPlayer对象本身,而控制器类则是我所有按钮的函数。 我一直在试图找到关于这些事情的标准布局的东西,但我没有成功。如果我把它放在我唯一的另一个监听器(在TrackPlayer的构造函数中),我会得到一个错误,说控制器类中的setTime不能从静态上下文中引用。 –
我没有时间查看非现场资源,希望您在当前答案中有足够的信息,因为它可以帮助您确定正确的应用方法。对于将来的问题,您可能会考虑在问题中提供[mcve](http://stackoverflow.com/help/mcve),即可以复制和粘贴以便立即复制问题的完整的最小可编译代码。 – jewelsea
我添加了生成相同问题的最小代码。我相信我明白为什么会出现这个问题,但我不知道如何去解决问题。 –