我在将UI组件绑定到可观察对象上遇到麻烦,该可观察对象从http发布事件获取更新进度。我收到一个IllegalStateException
据我了解,问题是UI线程上没有发生绑定更新。我已经读过的答案说,我需要使用runAsync,然后指定一个UI块来更新UI组件,但是我对如何完成此操作感到困惑。
// View class
private val controller: ZumController by inject()
item("_Upload") {
isMnemonicParsing = true
action {
controller.uploadToServer()
}
}
bottom = label() {
useMaxWidth = true
padding = Insets(5.0, 10.0, 5.0, 10.0)
this.bind(controller.progress)
}
// Controller class
var progress = SimpleStringProperty("Select images to upload")
fun uploadToServer() {
images.forEach{ p ->
Fuel.upload("http://127.0.0.1:8089")
.add {FileDataPart(File(p), name = "file")}
.progress { readBytes, totalBytes ->
progress.value = (readBytes.toFloat() / totalBytes.toFloat() * 100).toString()}
.response { _ -> }
}
}
在函数调用(uploadToServer())返回之前需要进度时,如何确保在应用程序线程期间更新UI?抱歉,如果已经回答了这个问题,我仍然无法确切了解这里发生的情况。
答案 0 :(得分:0)
我通过以下更改解决了我的问题。我将FXTask传递给函数uploadToServer()。在这里,我带有带有HTTP POST请求的进度回调的updateMessage()。我不能说这是最好的方法,但是它可以工作。随时使用更清晰简洁的代码来更新此答案
item("_Upload") {
isMnemonicParsing = true
action {
runAsync {
controller.uploadToServer(this)
} ui {
}
}
}
fun uploadToServer(task: FXTask<*>) {
images.forEach{ p ->
Fuel.upload("http://127.0.0.1:8089")
.add {FileDataPart(File(p), name = "file")}
.progress { readBytes, totalBytes ->
val perComplete = readBytes.toFloat() / totalBytes.toFloat() * 100
task.updateMessage("Uploading $p %.2f".format(perComplete).plus("%"))
}
.response { _ -> }
}
}
答案 1 :(得分:0)
TornadoFX具有内置的TaskStatus
对象,该对象具有用于任务进度的属性。您可以将TaskStatus
对象中的一个或多个属性绑定到任何UI元素,只需在控制器函数内调用updateProgress
。您甚至不需要传递TaskStatus
对象,因为如果没有,将使用默认实例。
框架中有一些测试应用程序可以执行此操作:
https://github.com/edvin/tornadofx/blob/master/src/test/kotlin/tornadofx/testapps/AsyncProgressApp.kt https://github.com/edvin/tornadofx/blob/master/src/test/kotlin/tornadofx/testapps/TaskStatusTest.kt
也就是说,一种从任何其他线程更新UI的快速而肮脏的解决方案就是将UI操作代码包装在runLater {}
中。例如,这对于更新标签同样有效。