2016-03-01 3 views
0

Я новичок в 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="&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, потому что он пытается инициализировать слушателя с текущим временем и продолжительностью, однако объект игрок не был создан еще (как песня не воспроизводится с самого начала , только при выборе и нажатии воспроизведения) - если это так, как я могу добавить слушателя?

Редактирование: Хорошо, поэтому я проверил, что вызывает NullPointerException, и это игрок, который является нулевым, поскольку программа запускается, когда я это делаю.

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

Однако, когда я это делаю, слушатель не инициализируется, поскольку метка runTime не изменяется вообще. Это моя проблема, которую я пытаюсь решить. Как я могу это исправить?

ответ

1

Non-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 включает в себя два компонента: пользовательский медиаплеер и ярлык продолжительности.

В этом случае слушатель находится в контроллере для всеобъемлющего файла FXML, который включает в себя медиа-плеер и метку продолжительности и настроить во время initialize() вызова для этого контроллера.

FXML На основе образца

В общем, что-то вроде этого для общего повторного использования вы можете создать пользовательский элемент управления, как описано выше, но для краткости этот пример будет просто использовать MediaView и этикетки контроля в построенных довольно чем пользовательский контроль.

<?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> 

App

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 с такими функциями, как воспроизведение, остановка и сам объект TrackPlayer от конструктора при передаче пути к файлу и класс контроллера, где у меня есть функции для всех кнопок. Я пытался найти что-то о стандартной компоновке таких вещей, но я не был успешным. Если бы я разместил его ниже моего другого другого слушателя (в конструкторе TrackPlayer), я бы получил ошибку, говоря, что setTime в классе контроллера не может ссылаться на статический контекст. –

+1

У меня нет времени на просмотр ресурса вне сайта, надеюсь, у вас будет достаточно информации в текущем ответе, поскольку он поможет вам определить правильный подход для вашего приложения. Для будущих вопросов вы можете рассмотреть вопрос о поставке [mcve] (http://stackoverflow.com/help/mcve) в вопросе, т. Е. Полного минимального компилируемого кода, который кто-то может скопировать и вставить, чтобы немедленно воспроизвести проблему. – jewelsea

+0

Я добавил минимальный код, который создает ту же проблему. Полагаю, я понимаю, почему проблема возникает, но я не знаю, как ее исправить. –

Смежные вопросы