2016-03-01 102 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

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