问题
Good day. I was wondering if there is a convenient or streamlined way of binding FXTask
's messageProperty
and runningProperty
to Label
's textProperty
and visibleWhen
property accordingly without coupling FXTask
and Label
themselves?
For example in the sample app below, I'm binding messageProperty
by coupling label's reference to a task, which introduces an extra lateinit var statusLabel
. Similarly, I'm binding runningProperty
by coupling task's reference to a label which introduces an extra val task
.
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)
回答1:
There is a TaskStatus
object that can be passed into runAsync
. This object has all the interesting properties of the task you're running. No need to subclass Task
either :)
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)
}
}
}
You could even use the automatically available taskStatus simply by injecting it. If you don't pass a specific instance of TaskStatus to runAsync, you'll get the default instance. Therefor this also works: (Difference is TaskStatus is injected, and no instance of TaskStatus is passed to 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)
}
}
}
来源:https://stackoverflow.com/questions/51428584/binding-fxtask-message-to-label-without-component-coupling-in-tornadofx