我是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
我添加了生成相同問題的最小代碼。我相信我明白爲什麼會出現這個問題,但我不知道如何去解決問題。 –