簡體   English   中英

JavaFx。 如何恢復?

[英]JavaFx. How to resume?

我正在為文本編寫時間表:

用法:

Text text = new Text();
......
group.getChildren().addAll(text);
    root.getChildren().addAll(group);

tl.play();

這很好。 如果要暫停並繼續播放動畫,請tl.pause(); tl.play(); 可以做到的。

現在,我要使動畫從頭開始,並使用tl.stop(); tl.playFromStart(); 但是這種組合的效果與tl.pause();的效果相同tl.pause(); tl.play();

我的問題是,為什么tl.playFromStart(); 無法正常工作,如何恢復動畫?

Timeline的工作方式

Timeline表示執行動畫的時間段。 Timeline包含KeyFrame集合。 每個關鍵KeyFrame

  • 必須Timeline (您傳入的Duration對象)中指定一個時間點
  • 還可以選擇指定KeyValue集合,這些集合包括WritableValue (例如, Property )和該時間點那些WritableValue的目標值
  • 可以選擇以EventHandler<ActionEvent>的形式指定要執行的動作

Timeline具有currentTime屬性,該屬性(當然)在Timeline播放時隨着時間的流逝而向前推進。 pause()將停止currentTime ,將其固定為當前值。 stop()將停止的進展currentTime並設置currentTime回零。

如果Timeline具有指定KeyValueKeyFrame ,則隨着currentTime更改,在KeyValue指定的WritableValue將被設置為取決於currentTime值。 (特別是,如果WritableValue是可插值的,則將在指定該WritableValue KeyValue的兩個相鄰KeyFrames之間插值。否則,該值將被設置為指定該WritableValue的值的“最新” KeyFrame 。)

如果Timeline具有指定動作的KeyFrameEventHandler<ActionEvent> ),則當currentTime超過該KeyFrame指定的時間時,將調用該動作。

為什么您的代碼無法與stop()playFromStart()

在您的情況下,您的KeyFrame指定了一個動作,該動作將新的變換添加到節點的變換列表中。 請注意,這完全不依賴於currentTime ,只是每次currentTime達到0.04 seconds ,都會添加一個新的轉換(加上您未顯示其實現的方法shiftAndScale )。 因此,如果您在時間軸上stop() ,則currentTime將重置為零,但是由於該原因,該節點不會發生任何事情。 (實際上,無論如何, currentTime僅在00.04秒之間變化。)

您的代碼的其他問題

您的代碼存在問題,因為您存在內存泄漏。 Node維護TransformObservableList 您正在添加到此列表(經常),但從不刪除任何內容。 Node非常智能:它保留了一個隱藏的矩陣,該矩陣是所有變換的凈效果; 當您添加新的轉換時,它將存儲在列表中,然后使用簡單的矩陣乘法更新“ net”矩陣。 因此,您在這里不會看到任何計算性能問題:從該角度來看,它可以很好地擴展。 但是,它確實存儲了所有單個轉換(例如,因為它支持稍后將其刪除),因此,如果讓此轉換運行足夠長的時間, 最終將耗盡內存。

您的代碼的另一個(也許是次要的)問題是,當您組合所有這些轉換時,您正在執行很多浮點運算。 任何舍入錯誤最終都會累積。 您應該嘗試找到一種避免舍入誤差累積的技術。

修復代碼的方法

要解決此問題,您有兩種選擇:

如果動畫是“自然循環”的(意味着動畫在某個固定時間(例如旋轉)后返回其初始狀態),則只需根據該自然持續時間定義Timeline 僅以旋轉為例,您可以執行以下操作:

double secondsPerCompleteCycle = (360.0 / 0.75) * 0.04 ;
Rotate rotation = new Rotate(0, new Point3D(1, 0, 0));
group.getTransforms().add(rotation);
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(secondsPerCompleteCycle), 
    new KeyValue(rotation.angleProperty(), 360, Interpolator.LINEAR)));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();

現在timeline.stop()會將currentTime設置為零,這將具有將旋轉角度設置回其初始值(也為零)的效果。

如果動畫不是自然重復的,我將使用(整數類型)計數器以您選擇的任何時間單位跟蹤“當前幀”,然后將變換的值綁定到計數器。 使用相同的示例,您可以

double degreesPerFrame = 0.75 ;
LongProperty frameCount = new SimpleLongProperty();
Rotate rotation = new Rotate(0, new Point3D(1, 0, 0));
group.getTransforms().add(rotation);
rotation.angleProperty().bind(frameCount.multiply(degreesPerFrame));

Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(0.04), e -> 
    frameCount.set(frameCount.get() + 1)));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();

// to reset to the beginning:
timeline.stop();
frameCount.set(0L);

您還可以考慮使用AnimationTimer ,具體取決於您的確切要求。 不過,我會首先嘗試其中一種技術。

在您的情況下,代數變得非常復雜(無論如何對我來說都是非常復雜的)。 每個動作將三個變換添加到該節點。 平移,比例尺和繞x軸的旋轉。 這些的4x4矩陣表示為:

1 0 0 tx
0 1 0 ty
0 0 1 0
0 0 0 1

對於翻譯,

sx  0 0 0 
 0 sy 0 0
 0  0 1 0
 0  0 0 1

規模,以及

1      0       0 0
0 cos(t) -sin(t) 0
0 sin(t)  cos(t) 0
0      0       0 1

旋轉。

雖然計算這三個的凈效應並不太難(只需將它們相乘),但計算任意次數應用這些凈矩陣就超出了我的范圍(也許...)。 此外,您在x方向上平移的量正在變化,這幾乎是不可能的。

因此,解決此問題的另一種方法是定義單個轉換並將其應用於節點,然后在每個事件上對其進行修改。 這看起來像

Affine transform = new Affine() ; // creates identity transform
node.getTransforms().add(transform);

Timeline timeline = new Timeline(Duration.seconds(0.04), event -> {
    double shiftX = ... ;
    double shiftY = ... ;
    double scaleX = ... ;
    double scaleY = ... ;
    double angle = 0.75 ;
    Affine change = new Affine();
    change.append(new Translate(shiftX, shiftY));
    change.append(new Scale(scaleX, scaleY));
    change.append(new Rotate(angle, new Point3D(1, 0, 0)));
    transform.append(change);
});

timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();

如上所述, stop()pause()將具有(幾乎)相同的效果。 (唯一的區別是再次播放時第一次更新的時間,對於stop()來說是0.04秒,對於pause()來說會更短-暫停下一次更新之前所剩下的時間。) “重置”動畫,您只需

timeline.stop();
transform.setToIdentity(); // resets to beginning

注意,通過使用這種技術,該節點僅對其應用了一次變換;對於該節點,僅進行一次變換。 我們只是隨着進展而更新該轉換。 舍入誤差仍然會累積,但是至少代數是可行的:)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM