2013-10-23 62 views
3

我有一個應用程序具有帶有一些雙精度值的組合框。用戶可以選擇任何值。該應用程序附有一個「TimeLine」,它將在控制檯上打印語句。下面是sscce。應該發生的是,應該打印從組合框中選擇的選項的文本。請建議。JavaFX:將時間軸的持續時間綁定到屬性

package just.to.test; 

import javafx.animation.KeyFrame; 
import javafx.animation.Timeline; 
import javafx.application.Application; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.scene.control.ComboBox; 
import javafx.stage.Stage; 
import javafx.util.Duration; 

public class TimerSample extends Application { 
    public static void main(String[] args) { 
     Application.launch(args); 
    } 

    @Override 
    public void start(Stage primaryStage) { 
     primaryStage.setTitle("Text Fonts"); 

     Group g = new Group(); 
     Scene scene = new Scene(g, 150, 100); 

     ObservableList<Double> data = FXCollections.observableArrayList(); 

     data.add(5.0); 
     data.add(10.0); 
     data.add(15.0); 
     data.add(20.0); 

     ComboBox<Double> timeOptions = new ComboBox<Double>(data); 
     timeOptions.getSelectionModel().selectFirst(); 

     g.getChildren().addAll(timeOptions); 

     primaryStage.setScene(scene); 
     primaryStage.show(); 

     final double timerInterval = timeOptions.getSelectionModel().getSelectedItem(); 

     KeyFrame keyFrame = new KeyFrame(Duration.seconds(timerInterval), 
      new EventHandler<ActionEvent>() { 
       @Override 
       public void handle(ActionEvent event) { 
        System.out.println("This is called every " 
         + timerInterval + " seconds"); 
       } 
      }); 

     Timeline timerThread = new Timeline(keyFrame); 
     timerThread.setCycleCount(Timeline.INDEFINITE); 
     timerThread.play(); 
    } 
} 

回答

7

不能在時間軸的時間綁定到一個屬性,因爲一個關鍵幀的時間軸中的持續時間不是一個屬性,你只能綁定屬性的屬性。

你需要做的,而不是什麼是監聽的組合框的值發生變化,並觸發當用戶選擇一個新的持續時間創建新的持續時間新的關鍵幀。您也無法修改正在運行的時間軸的關鍵幀,因此必須在設置時間軸的新關鍵幀之前停止時間軸,然後在新的關鍵幀設置完成後開始時間軸。

示例代碼

import javafx.animation.*; 
import javafx.application.Application; 
import javafx.beans.value.*; 
import javafx.collections.*; 
import javafx.event.*; 
import javafx.scene.*; 
import javafx.scene.control.ComboBox; 
import javafx.stage.Stage; 
import javafx.util.Duration; 

public class TimerSample extends Application { 
    public static void main(String[] args) { 
     Application.launch(args); 
    } 

    @Override 
    public void start(Stage stage) { 
     Group g = new Group(); 
     Scene scene = new Scene(g, 150, 100); 

     ComboBox<Double> timerOptions = createTimerOptions(
       0.5, 1.0, 1.5, 2.0 
     ); 
     g.getChildren().addAll(timerOptions); 

     createTimer(timerOptions); 

     stage.setScene(scene); 
     stage.show(); 
    } 

    private ComboBox<Double> createTimerOptions(double... options) { 
     ObservableList<Double> data = FXCollections.observableArrayList(); 

     for (Double option: options) { 
      data.add(option); 
     } 

     return new ComboBox<Double>(data); 
    } 

    private void createTimer(ComboBox<Double> timeOptions) { 
     final Timeline timer = new Timeline(); 
     timer.setCycleCount(Timeline.INDEFINITE); 

     timeOptions.valueProperty().addListener(new ChangeListener<Double>() { 
      @Override 
      public void changed(ObservableValue<? extends Double> observable, Double oldValue, Double newValue) { 
       resetTimer(timer, newValue); 
      } 
     }); 

     timeOptions.getSelectionModel().selectFirst(); 
    } 

    private void resetTimer(Timeline timer, final double timerInterval) { 
     KeyFrame keyFrame = new KeyFrame(
      Duration.seconds(timerInterval), 
      new EventHandler<ActionEvent>() { 
       @Override 
       public void handle(ActionEvent event) { 
        System.out.println(
          "This is called every " 
            + timerInterval 
            + " seconds" 
        ); 
       } 
      } 
     ); 

     timer.stop(); 
     timer.getKeyFrames().setAll(
       keyFrame 
     ); 
     timer.play(); 
    } 
} 

只是想知道,在性能方面是由於添加新的關鍵幀,在組合框的值的每一個變化要重得多。

在這種情況下,不要過於擔心性能 - 這是一種高效的操作。

沒有比因爲關鍵幀immutable objects創造新的關鍵幀沒有其他解決辦法。

您可以先構建關鍵幀,或者將它們放在類似於LRU cache的東西中,就像您懶惰地構建它們一樣,但總體而言,所涉及的額外複雜性幾乎肯定不值得。

+0

的偉大工程。謝謝。但只是想知道性能是否明智,因爲隨着組合框值的每次變化都添加一個新的關鍵幀。 – Aspirant

+0

根據其他問題更新了答案。 – jewelsea

+0

'rateProperty()'不會更清潔嗎? – Mordechai

2

所有動畫有rateProperty()它可以在一個正在運行的動畫來改變!

這似乎是一個更清潔的解決方案:

private void createTimer(ComboBox<Double> timeOptions) { 
    Timeline timer = new Timeline(
      new KeyFrame(Duration.seconds(1), 
      evt-> System.out.println(
         "This is called every " 
           + timeOptions.getValue() 
           + " seconds" 
       )); 

    timer.setCycleCount(Timeline.INDEFINITE); 
    timer.rateProperty() 
     .bind(new SimpleDoubleProperty(1.0) 
     .divide(timeOptions.valueProperty())); 

    timeOptions.getSelectionModel().selectFirst(); 
}