为什么我的 tornadoFX ObservableList 没有收到更新?
Why does my tornadoFX ObservableList not receive updates?
我有一个简单的 tornadoFX 程序,可以在屏幕上的随机位置生成一些圆圈。但是,绘制了 none 个圆圈。我添加了一些调试代码来在绘制圆时打印一条线,它只打印一次。
我希望圆圈以 100 毫秒的间隔出现,当我单击 "Add actor" 按钮时也是如此。
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))
}
}
}
}
}
}
奇怪的是,如果我在画圆的代码中放置一个断点,就会画出圆并打印调试行。
一些观察:
调用 someList.observable()
将创建一个由底层列表支持的可观察列表,但底层列表上的突变不会发出事件。您应该立即将 actors
初始化为可观察列表。
对可观察列表的访问必须发生在UI线程上,因此您需要在runLater
.
中包装突变调用
对于尝试 运行 你的例子的人 - 你没有包含样式表,但在你的 App
subclass 中引用了一个样式表,所以 IDEA很可能会导入 TornadoFX Stylesheet
class。这不会有好结果:)
also
调用没有效果,所以我去掉了
我将您的代码更新为最佳实践,例如关于如何创建根节点:)
考虑到这些要点的更新示例如下所示:
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))
}
}
}
}
我有一个简单的 tornadoFX 程序,可以在屏幕上的随机位置生成一些圆圈。但是,绘制了 none 个圆圈。我添加了一些调试代码来在绘制圆时打印一条线,它只打印一次。
我希望圆圈以 100 毫秒的间隔出现,当我单击 "Add actor" 按钮时也是如此。
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))
}
}
}
}
}
}
奇怪的是,如果我在画圆的代码中放置一个断点,就会画出圆并打印调试行。
一些观察:
调用
someList.observable()
将创建一个由底层列表支持的可观察列表,但底层列表上的突变不会发出事件。您应该立即将actors
初始化为可观察列表。对可观察列表的访问必须发生在UI线程上,因此您需要在
runLater
. 中包装突变调用
对于尝试 运行 你的例子的人 - 你没有包含样式表,但在你的
App
subclass 中引用了一个样式表,所以 IDEA很可能会导入 TornadoFXStylesheet
class。这不会有好结果:)also
调用没有效果,所以我去掉了我将您的代码更新为最佳实践,例如关于如何创建根节点:)
考虑到这些要点的更新示例如下所示:
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))
}
}
}
}