import javafx.animation.AnimationTimer import javafx.application.Application import javafx.application.Platform import javafx.geometry.Pos import javafx.scene.canvas.GraphicsContext import javafx.scene.control.RadioButton import javafx.scene.paint.Color import tornadofx.* import java.util.* import kotlin.math.PI import kotlin.math.cos import kotlin.math.sin fun main(args: Array<String>) { Application.launch(TestApp::class.java, *args) } class TestApp : App(TestView::class) class TestView : View("逐個顯示圖形") { val isRun = booleanProperty() val pNums = intProperty() val aniMate = AniTimer() var t = -PI var renderedList: MutableList<Point> = LinkedList<Point>() val step= doubleProperty(0.01) lateinit var context: GraphicsContext override val root = borderpane { top = hbox(10) { style { alignment = Pos.CENTER } label("點密度") togglegroup { listOf(0.01, 0.03, 0.05, 0.07, 0.1).map { v -> radiobutton(v.toString(), this, v) { if (v === 0.01) isSelected = true } } selectedToggleProperty().addListener { _, _, newValue -> // step.value = (selectedToggle as RadioButton).text.toDouble() step.value = (newValue as RadioButton).text.toDouble() } } button("start") { isRun.addListener { _,_,isrun-> if (isrun) this.text = "Pause" else this.text = "Start" } action { if (isRun.value) { aniMate.stop() this.text = "Start" isRun.value = false } else { t = -PI renderedList.clear() pNums.value=0 aniMate.start() this.text = "Pause" isRun.value = true } } } label(pNums.stringBinding { "當前點數:$it" }) } center = canvas(800.0, 600.0) { style { alignment = Pos.CENTER } context = this.graphicsContext2D paddingAll = 30 } } inner class AniTimer : AnimationTimer() { var lastTime = 0L val r = 10.0 var syncLock = Any() override fun handle(now: Long) { if ((now - lastTime) > 10000000) { lastTime = now } else { return } Platform.runLater { val y = 200 + (2 * cos(t) - cos(2 * t)) * -80 val x = 400 + (2 * sin(t) - sin(2 * t)) * 100 val p = Point(x, y) // 鎖住,防止其餘線程修改 synchronized(syncLock) { // 添加歷史記錄 renderedList.add(p) // 清屏 context.fill = Color.WHITE context.clearRect(0.0, 0.0, 800.0, 600.0) context.fill = Color.RED // 渲染點 for (point in renderedList) { context.fillOval(point.x, point.y, r, r) } pNums.value += 1 t += step.value // 控制點的數量 if (t > PI) { aniMate.stop() isRun.value=false } } } } } } class Point(val x: Double, val y: Double)