在 TornadoFX 中没有组件耦合的情况下将“FXTask”消息绑定到“Label”

Binding `FXTask` message to `Label` without component coupling in TornadoFX

美好的一天。我想知道是否有一种方便或简化的方式将 FXTaskmessagePropertyrunningProperty 绑定到 LabeltextPropertyvisibleWhen 属性 因此没有耦合 FXTaskLabel 本身?

例如,在下面的示例应用程序中,我通过将标签的引用耦合到任务来绑定 messageProperty,这会引入一个额外的 lateinit var statusLabel。同样,我通过将任务的引用耦合到引入额外 val task.

的标签来绑定 runningProperty
class DummyView : View("Dummy View") {
    override val root = vbox {
        lateinit var statusLabel: Label

        val task = object : Task<Void>() {
            public override fun call(): Void? {
                Platform.runLater { statusLabel.textProperty().bind(messageProperty()) } // label coupling

                updateMessage("Initializing task...")
                (1..3).forEach {
                    Thread.sleep(1000)
                    updateMessage("Doing task: $it...")
                }

                Thread.sleep(1000)
                updateMessage("Task done")
                Thread.sleep(1000)
                return null
            }
        }

        button("Do task") {
            action {
                Thread(task).apply {// task coupling
                    isDaemon = true
                }.start()
            }
        }
        statusLabel = label("Status") {
            visibleWhen(task.runningProperty()) // task coupling
        }
    }
}

class DummyApp : App(DummyView::class)

有一个 TaskStatus 对象可以传入 runAsync。该对象具有您 运行 任务的所有有趣属性。也不需要子类化 Task :)

class DummyView : View("Dummy View") {
    val taskStatus = TaskStatus()

    override val root = vbox {
        button("Do task") {
            action {
                runAsync(taskStatus) {
                    updateMessage("Initializing task...")
                    (1..3).forEach {
                        Thread.sleep(1000)
                        updateMessage("Doing task: $it...")
                    }
                    Thread.sleep(1000)
                    updateMessage("Task done")
                    Thread.sleep(1000)
                }
            }
        }
        label(taskStatus.message) {
            visibleWhen(taskStatus.running)
        }
    }
}

您甚至可以通过注入来使用自动可用的 taskStatus。如果您不将 TaskStatus 的特定实例传递给 runAsync,您将获得默认实例。因此这也适用:(不同之处在于注入了 TaskStatus,并且没有 TaskStatus 实例传递给 runAsync)

class DummyView : View("Dummy View") {
    val taskStatus: TaskStatus by inject()

    override val root = vbox {
        button("Do task") {
            action {
                runAsync {
                    updateMessage("Initializing task...")
                    (1..3).forEach {
                        Thread.sleep(1000)
                        updateMessage("Doing task: $it...")
                    }
                    Thread.sleep(1000)
                    updateMessage("Task done")
                    Thread.sleep(1000)
                }
            }
        }
        label(taskStatus.message) {
            visibleWhen(taskStatus.running)
        }
    }
}