为什么我的tornadoFX ObservableList无法接收更新?

Cru*_*mmy 1 kotlin tornadofx

我有一个简单的tornadoFX程序,该程序会在屏幕上的随机位置生成一些圆圈。但是,没有一个圆圈被绘制。我添加了一些调试代码以在绘制圆时打印一条线,并且只打印一次。

我希望圆圈以100ms的间隔出现,以及当我单击“添加演员”按钮时出现。

private const val WINDOW_HEIGHT = 600
private const val WINDOW_WIDTH = 1024

fun main(args: Array<String>) {
    Application.launch(MainApp::class.java, *args)
}

class MainApp : App(WorldView::class, Stylesheet::class)

data class Actor(val x: Double, val y: Double)

class WorldView: View("Actor Simulator") {
    override val root = VBox()
    private val actors = ArrayList<Actor>(0)

    init {
        tornadofx.runAsync {
            (0..100).forEach {
                val x = ThreadLocalRandom.current().nextDouble(0.0, WINDOW_WIDTH.toDouble())
                val y = ThreadLocalRandom.current().nextDouble(0.0, WINDOW_HEIGHT.toDouble())
                actors.add(Actor(x, y))
                Thread.sleep(100)
            }
        }
    }

    init {
        with(root) {
            stackpane {
                group {
                    bindChildren(actors.observable()) {
                        circle {
                            centerX = it.x
                            centerY = it.y
                            radius = 10.0
                            also {
                                println("drew circle")
                            }
                        }
                    }
                }
                button("Add actor") {
                    action {
                        actors.add(Actor(0.0, 0.0))
                    }
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

奇怪的是,如果我在画圆的代码中放置了一个断点,那么会画圆,并且会打印调试行。

Edv*_*yse 5

一些观察:

  1. 调用someList.observable()将创建一个由基础列表支持的可观察列表,但是基础列表上的突变不会发出事件。您应该立即将其初始化actors为可观察的列表。

  2. 对可观察列表的访问必须在UI线程上进行,因此您需要将突变调用包装在中runLater

  3. 对于尝试运行您的示例的人-您没有包括样式表,但是在App子类中引用了样式表,因此IDEA很可能会导入TornadoFX Stylesheet类。这不会很好:)

  4. also呼叫无效,因此我将其删除。

  5. 我将您的代码更新为此处和此处的最佳实践,例如关于如何创建根节点的信息:)

考虑这些要点的更新示例如下所示:

private const val WINDOW_HEIGHT = 600.0
private const val WINDOW_WIDTH = 1024.0

class MainApp : App(WorldView::class)

data class Actor(val x: Double, val y: Double)

class WorldView : View("Actor Simulator") {

    private val actors = FXCollections.observableArrayList<Actor>()

    override fun onDock() {
        runAsync {
            (0..100).forEach {
                val x = ThreadLocalRandom.current().nextDouble(0.0, WINDOW_WIDTH.toDouble())
                val y = ThreadLocalRandom.current().nextDouble(0.0, WINDOW_HEIGHT.toDouble())
                runLater {
                    actors.add(Actor(x, y))
                }
                Thread.sleep(100)
            }
        }
    }

    override val root = stackpane {
        setPrefSize(WINDOW_WIDTH, WINDOW_HEIGHT)
        group {
            bindChildren(actors) {
                circle {
                    centerX = it.x
                    centerY = it.y
                    radius = 10.0
                    println("drew circle")
                }
            }
        }
        button("Add actor") {
            action {
                actors.add(Actor(0.0, 0.0))
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)