Я новичок в Java и JavaFX - я делаю небольшое приложение для проигрывателя и нахожу его задачей получить таймер продолжительности для отображения на ярлыке на моем дисплее.Получение класса слушателя для изменения значений метки в контроллере
Моей последней попыткой было создать класс 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 Контроллер
@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, потому что он пытается инициализировать слушателя с текущим временем и продолжительностью, однако объект игрок не был создан еще (как песня не воспроизводится с самого начала , только при выборе и нажатии воспроизведения) - если это так, как я могу добавить слушателя?
Редактирование: Хорошо, поэтому я проверил, что вызывает NullPointerException, и это игрок, который является нулевым, поскольку программа запускается, когда я это делаю.
if (player != null) {
player.currentTimeProperty().addListener(observable -> {
runTime.setText(player.getCurrentTime()
+ "/"
+ player.getTotalDuration());
});
}
Однако, когда я это делаю, слушатель не инициализируется, поскольку метка runTime не изменяется вообще. Это моя проблема, которую я пытаюсь решить. Как я могу это исправить?
Я просто не понимаю одну вещь, где я должен поместить слушателя? У меня есть класс TrackPlayer с такими функциями, как воспроизведение, остановка и сам объект TrackPlayer от конструктора при передаче пути к файлу и класс контроллера, где у меня есть функции для всех кнопок. Я пытался найти что-то о стандартной компоновке таких вещей, но я не был успешным. Если бы я разместил его ниже моего другого другого слушателя (в конструкторе TrackPlayer), я бы получил ошибку, говоря, что setTime в классе контроллера не может ссылаться на статический контекст. –
У меня нет времени на просмотр ресурса вне сайта, надеюсь, у вас будет достаточно информации в текущем ответе, поскольку он поможет вам определить правильный подход для вашего приложения. Для будущих вопросов вы можете рассмотреть вопрос о поставке [mcve] (http://stackoverflow.com/help/mcve) в вопросе, т. Е. Полного минимального компилируемого кода, который кто-то может скопировать и вставить, чтобы немедленно воспроизвести проблему. – jewelsea
Я добавил минимальный код, который создает ту же проблему. Полагаю, я понимаю, почему проблема возникает, но я не знаю, как ее исправить. –