AnimationTimer
JavaFX有三类动画实现方式:Transition,TimeLine和AnimationTimer。
AnimationTimer看起来像是一个计时器,其实他更适合叫做心跳循环。JavaFX绘图的每一帧都会自动条用AnimationTimer. AnimationTimer是一个抽象类。实现该类需要实现一个函数handle,其参数为调用时的nanoTime()。
public abstract void handle(long var1);
public void start();
public void stop();
AnimationTimer的start和stop函数分别是开始和停止handel被系统调用。
AnimationTimer的例子
实现一个FPS记录程序。这个例子中,我们点击开始按钮,下方标签的文字就会逐渐变得透明。而程序还同时记录当前的FPS,显示在图中,当前的FPS在图的标签中也会同步更新。
package com.example.timerdemo1
import javafx.animation.AnimationTimer
import javafx.application.Application
import javafx.beans.binding.Bindings
import javafx.beans.property.SimpleDoubleProperty
import javafx.beans.property.SimpleObjectProperty
import javafx.collections.FXCollections
import javafx.geometry.Pos
import javafx.scene.Scene
import javafx.scene.chart.LineChart
import javafx.scene.chart.NumberAxis
import javafx.scene.chart.XYChart
import javafx.scene.control.Button
import javafx.scene.control.Label
import javafx.scene.layout.VBox
import javafx.scene.text.Font
import javafx.stage.Stage
import kotlin.math.roundToLong
class AnimationTimerSample : Application() {
private var op = SimpleDoubleProperty(1.0)
private val dtValues = SimpleObjectProperty(
FXCollections.observableList(mutableListOf<XYChart.Data<Number, Number>>())
)
private val fps = SimpleDoubleProperty(0.0)
override fun start(st: Stage) {
initUI(st)
}
private fun initUI(st: Stage) {
val tm = TimerMethod(op.value)
val sp = VBox(10.0).apply {
alignment = Pos.CENTER
children.add(Button("开始").apply {
font = Font.font(24.0)
disableProperty().bind(
Bindings.createBooleanBinding(
{
op.value > 0 && op.value < 1
}, op
)
)
setOnAction {
if (op.value <= 0 || op.value >= 1.0) {
op.value = 1.0
fps.value = 0.0
dtValues.value.clear()
tm.start()
}
}
})
children.add(Label("我是就要变得透明的大字!").apply {
font = Font.font(36.0)
opacityProperty().bind(op)
})
children.add(LineChart<Number, Number>(
NumberAxis(0.0, tm.maximumCount, tm.maximumCount / 10.0),
NumberAxis(0.0, 200.0, 20.0)
).apply {
animated = false
createSymbols = false
val dtLine = XYChart.Series<Number, Number>()
dtLine.nameProperty().bind(Bindings.concat("当前FPS:", fps.asString().concat(" 1/s")))
xAxis.label = "计数"
yAxis.label = "FPS (1/s)"
dtLine.dataProperty().bind(dtValues)
dtValues.value.add(XYChart.Data(0, 0))
data.add(dtLine)
})
}
val sc = Scene(sp, 800.0, 600.0)
st.title = "AnimationTimer示例"
st.scene = sc
st.show()
}
private inner class TimerMethod(private val maxT: Double) : AnimationTimer() {
private var lastTime: Long = -1
private val dt = 0.01
val maximumCount: Double
get() = maxT / dt
override fun handle(now: Long) {
if (lastTime <= -1) {
dtValues.value.clear()
} else {
val n = dtValues.value.size
val dt = now - lastTime
fps.value = (1e9 / dt).roundToLong().toDouble()
dtValues.value.add(XYChart.Data(n, fps.value))
}
lastTime = now
tick()
}
private fun tick() {
op.value -= dt
if (op.value <= 0) {
stop()
}
}
}
}
fun main() {
Application.launch(AnimationTimerSample::class.java)
}
就是这么简单!
|