【问题标题】:Label text isn't updating even though UI thread seems to be responsive即使 UI 线程似乎是响应式的,标签文本也没有更新
【发布时间】:2017-10-23 07:35:14
【问题描述】:

我正在使用 JDK 8u121 上的 Kotlin 1.1.51 使用 TornadoFX 1.7.11 构建应用程序。

我正在尝试在单独的线程中执行长时间运行的任务,并使用进度条和标签在 UI 中显示进度。奇怪的是,标签没有更新。我想也许我以某种方式在 UI 线程上运行了任务并且它被卡住了,但是进度条工作并且 UI 是响应式的(控件工作等)。

我还尝试使用 ScenicView 手动编辑标签,并且成功了。我没办法了,你们能帮忙吗?

这里有一些简化的代码sn-ps:

主视图.kt
class MainView : View("") {
    private val controller: MainController by inject()

    override val root = borderpane {
        bottom(TasksView::class)
    }

    init {
        controller.reloadTranslations().completed.onChange {
            // do some lightweight UI stuff
        }
    }
}
主控制器.kt
class MainController : Controller() {
    private val tasksController: TasksController by inject()

    fun reloadTranslations(): TaskStatus {
        val task = TaskStatus()
        tasksController.tasks.add(task)
        runAsync(task) {
            updateMessage(messages["loadingTranslations"])
            BibxCache.rebuild().subscribe {
                updateMessage(messages["loadingTranslations"] + " " + it.loaded)  // for debugging
                updateProgress(it.loaded.toLong(), it.total.toLong())
            }
        }
        return task
    }

    fun getTranslations() = BibxCache.values.toSortedSet()
}
任务视图.kt
class TasksView : View() {
    override val root = vbox()

    val controller: TasksController by inject()

    init {
        controller.tasks.onChange {
            root.clear()
            controller.tasks.map { TaskRow(it) }.forEach { root.add(it) }
        }
    }
}

class TaskRow(task: TaskStatus) : HBox() {
    init {
        val progressBar = ProgressBar(task.progress.get())
        progressBar.bind(task.progress)
        val label = Label(task.message.get())
        label.bind(task.message)
        task.message.onChange { println(it) }  // for debugging
        children.addAll(
                progressBar,
                Label(task.message.get())
        )
    }
}
任务控制器.kt
class TasksController : Controller() {
    val tasks: ObservableList<TaskStatus> = FXCollections.observableArrayList()

    init {
        tasks.onChange { change ->
            change.next()
            change.addedSubList.forEach { added ->
                added.completed.onChange {
                    tasks.remove(added)
                }
            }
        }
    }
}

【问题讨论】:

    标签: multithreading kotlin javafx-8 tornadofx


    【解决方案1】:

    您的代码不可运行,但我基于这些概念创建了一个最小示例,并使用了更惯用的方法。

    class MainView : View("Tasks") {
        private val mainController: MainController by inject()
    
        override val root = borderpane {
            setPrefSize(600.0, 400.0)
            top {
                button("Start task").action {
                    mainController.reloadTranslations()
                }
            }
            bottom(TasksView::class)
        }
    }
    
    class MainController : Controller() {
        private val tasksController: TasksController by inject()
    
        fun reloadTranslations(): TaskStatus {
            val task = TaskStatus()
            tasksController.tasks.add(task)
            runAsync(task) {
                updateMessage(messages["loadingTranslations"] + " $this...")
                Thread.sleep(Random().nextInt(2000).toLong())
                updateMessage(messages["loadingTranslations"] + " $this - half way")
                updateProgress(50.0, 100.0)
                Thread.sleep(Random().nextInt(2000).toLong())
            }
            return task
        }
    }
    
    class TasksView : View() {
        val controller: TasksController by inject()
    
        override val root = vbox {
            bindChildren(controller.tasks) { task ->
                hbox {
                    progressbar(task.progress)
                    label(task.message)
                }
            }
        }
    }
    
    class TasksController : Controller() {
        val tasks: ObservableList<TaskStatus> = FXCollections.observableArrayList()
    
        init {
            tasks.onChange { change ->
                change.next()
                change.addedSubList.forEach { added ->
                    added.completed.onChangeOnce {
                        tasks.remove(added)
                    }
                }
            }
        }
    }
    

    这也可以用较少的宣传来完成,但我不知道你的应用程序的复杂性或要求,所以我尽可能少地改变它:)

    【讨论】:

    • 谢谢!我喜欢你的方法,它简洁、易读并且按预期工作。
    • 很高兴听到这个消息:))
    猜你喜欢
    • 2017-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-27
    • 1970-01-01
    • 1970-01-01
    • 2017-03-24
    • 1970-01-01
    相关资源
    最近更新 更多