从 ScalaFX 中的后台线程更新 UI
Updating UI from a background thread in ScalaFX
代码如下:
import javafx.event
import javafx.event.EventHandler
import scalafx.application.{Platform, JFXApp}
import scalafx.application.JFXApp.PrimaryStage
import scalafx.event.ActionEvent
import scalafx.scene.Scene
import scalafx.scene.control.{Button, Label}
import scalafx.Includes._
import scalafx.scene.layout.{VBox, HBox}
object Blocking extends JFXApp {
val statusLbl = new Label("Not started...")
val startBtn = new Button("Start") {
onAction = (e: ActionEvent) => startTask
}
val exitBtn = new Button("Exit") {
onAction = (e: ActionEvent) => stage.close()
}
val buttonBox = new HBox(5, startBtn, exitBtn)
val vBox = new VBox(10, statusLbl, buttonBox)
def startTask = {
val backgroundThread = new Thread {
setDaemon(true)
override def run = {
runTask
}
}
backgroundThread.start()
}
def runTask = {
for(i <- 1 to 10) {
try {
val status = "Processing " + i + " of " + 10
Platform.runLater(() => {
statusLbl.text = status
})
println(status)
Thread.sleep(1000)
} catch {
case e: InterruptedException => e.printStackTrace()
}
}
}
stage = new PrimaryStage {
title = "Blocking"
scene = new Scene {
root = vBox
}
}
}
当按下"start"按钮时,状态标签应该更新10次,但事实并非如此。从控制台可以看到后台线程确实在更新状态,但是这些都没有体现在UI中。为什么?
问题出在 Platform.runLater
的调用上。要使其正常工作,请将其更改为:
Platform.runLater {
statusLbl.text = status
}
runLater[R](op: => R)
将 returns 类型值 R
的代码块作为参数。您正在传递定义匿名函数的代码块。 runLater
正在创建一个函数,而不是执行它。
代码如下:
import javafx.event
import javafx.event.EventHandler
import scalafx.application.{Platform, JFXApp}
import scalafx.application.JFXApp.PrimaryStage
import scalafx.event.ActionEvent
import scalafx.scene.Scene
import scalafx.scene.control.{Button, Label}
import scalafx.Includes._
import scalafx.scene.layout.{VBox, HBox}
object Blocking extends JFXApp {
val statusLbl = new Label("Not started...")
val startBtn = new Button("Start") {
onAction = (e: ActionEvent) => startTask
}
val exitBtn = new Button("Exit") {
onAction = (e: ActionEvent) => stage.close()
}
val buttonBox = new HBox(5, startBtn, exitBtn)
val vBox = new VBox(10, statusLbl, buttonBox)
def startTask = {
val backgroundThread = new Thread {
setDaemon(true)
override def run = {
runTask
}
}
backgroundThread.start()
}
def runTask = {
for(i <- 1 to 10) {
try {
val status = "Processing " + i + " of " + 10
Platform.runLater(() => {
statusLbl.text = status
})
println(status)
Thread.sleep(1000)
} catch {
case e: InterruptedException => e.printStackTrace()
}
}
}
stage = new PrimaryStage {
title = "Blocking"
scene = new Scene {
root = vBox
}
}
}
当按下"start"按钮时,状态标签应该更新10次,但事实并非如此。从控制台可以看到后台线程确实在更新状态,但是这些都没有体现在UI中。为什么?
问题出在 Platform.runLater
的调用上。要使其正常工作,请将其更改为:
Platform.runLater {
statusLbl.text = status
}
runLater[R](op: => R)
将 returns 类型值 R
的代码块作为参数。您正在传递定义匿名函数的代码块。 runLater
正在创建一个函数,而不是执行它。