斯卡拉外汇。活绑定
ScalaFX. Live binding
我有一个简单的 UI window,只有一个文本节点, 显示当前时间并绑定到模型:
import model.Clock
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.beans.property.StringProperty
import scalafx.geometry.Insets
import scalafx.scene.Scene
import scalafx.scene.layout.HBox
import scalafx.scene.text.Text
import scalafx.Includes._
object Main extends JFXApp {
val clock = new Text()
clock.textProperty().bind( new StringProperty(Clock.curTime) )
stage = new PrimaryStage {
onShowing = handle { Clock.startClock }
title = "ScalaFX clock"
scene = new Scene {
content = new HBox {
padding = Insets(50, 80, 50, 80)
children = clock
}
}
}
}
还有一个模型:
import java.util.Date
import java.text.SimpleDateFormat
object Clock {
var curTime = ""
private lazy val dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss")
def startClock = {
/*A code, witch runs in another Thread and
changes curTime every 1 second skipped here.
Only one change of curTime for simplicity.
*/
curTime = dateFormat format new Date
}
}
我的问题是:当 curTime 变量改变时,UI 中的文本节点没有改变。
我猜它在 stratup 上渲染过一次。如何让文本节点每次都显示 curTime 的新值,curTime 改变了?
对不起我的英语:(
问题是 Clock.curTime
只是一个变量,其值会定期更新 - 它不是观察到的 属性,所以当它被更改时什么也不会发生。特别是,该变量与 Text
元素的内容
之间没有 link
您所做的是用该值初始化 StringProperty
- 但由于 属性 本身从未更新,标签也不会更新。我想你想做的是让 curTime
成为 StringProperty
而不仅仅是 String
。现在,每当您更改 属性 的值时,Text
元素的值将相应更改。
您应该注意,与 JavaFX/ScalaFX 的交互只能发生在 JavaFX 应用程序线程,所以如果您尝试从另一个线程更新 curTime
,您将 运行 遇到问题。实现这一目标的一种方法是将实际更新 curTime
的代码传递给 Platform.runLater
.
但是,更简单的方法是使用定时 ScalaFX 事件从 JavaFX/[ 中定期更新 curTime
=34=]ScalaFX,如下:
import model.Clock
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.geometry.Insets
import scalafx.scene.Scene
import scalafx.scene.layout.HBox
import scalafx.scene.text.Text
import scalafx.Includes._
object Main
extends JFXApp {
val clock = new Text()
// Clock.curTime is now a StringProperty, which we bind to clock's text. Since clock is
// created lazily, it starts the timer event, so we do not need startClock either.
clock.text <== Clock.curTime
// Create the stage & scene.
stage = new PrimaryStage {
title = "ScalaFX clock"
scene = new Scene {
content = new HBox {
padding = Insets(50, 80, 50, 80)
children = clock
}
}
}
}
在Clock.scala
中:
import java.util.Date
import java.text.SimpleDateFormat
import scalafx.animation.PauseTransition
import scalafx.application.Platform
import scalafx.beans.property.StringProperty
import scalafx.util.Duration
import scalafx.Includes._
// Object should be constructed lazily on the JFX App Thread. Verify that...
object Clock {
assert(Platform.isFxApplicationThread)
private val dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss")
val curTime = new StringProperty(getDate())
// Update the curTime property every second, using a timer.
// Note: 1,000 ms = 1 sec
val timer = new PauseTransition(Duration(1000))
timer.onFinished = {_ =>
curTime.value = getDate()
timer.playFromStart() // Wait another second, or you can opt to finish instead.
}
// Start the timer.
timer.play()
private def getDate() = dateFormat.format(new Date())
}
我有一个简单的 UI window,只有一个文本节点, 显示当前时间并绑定到模型:
import model.Clock
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.beans.property.StringProperty
import scalafx.geometry.Insets
import scalafx.scene.Scene
import scalafx.scene.layout.HBox
import scalafx.scene.text.Text
import scalafx.Includes._
object Main extends JFXApp {
val clock = new Text()
clock.textProperty().bind( new StringProperty(Clock.curTime) )
stage = new PrimaryStage {
onShowing = handle { Clock.startClock }
title = "ScalaFX clock"
scene = new Scene {
content = new HBox {
padding = Insets(50, 80, 50, 80)
children = clock
}
}
}
}
还有一个模型:
import java.util.Date
import java.text.SimpleDateFormat
object Clock {
var curTime = ""
private lazy val dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss")
def startClock = {
/*A code, witch runs in another Thread and
changes curTime every 1 second skipped here.
Only one change of curTime for simplicity.
*/
curTime = dateFormat format new Date
}
}
我的问题是:当 curTime 变量改变时,UI 中的文本节点没有改变。
我猜它在 stratup 上渲染过一次。如何让文本节点每次都显示 curTime 的新值,curTime 改变了?
对不起我的英语:(
问题是 Clock.curTime
只是一个变量,其值会定期更新 - 它不是观察到的 属性,所以当它被更改时什么也不会发生。特别是,该变量与 Text
元素的内容
您所做的是用该值初始化 StringProperty
- 但由于 属性 本身从未更新,标签也不会更新。我想你想做的是让 curTime
成为 StringProperty
而不仅仅是 String
。现在,每当您更改 属性 的值时,Text
元素的值将相应更改。
您应该注意,与 JavaFX/ScalaFX 的交互只能发生在 JavaFX 应用程序线程,所以如果您尝试从另一个线程更新 curTime
,您将 运行 遇到问题。实现这一目标的一种方法是将实际更新 curTime
的代码传递给 Platform.runLater
.
但是,更简单的方法是使用定时 ScalaFX 事件从 JavaFX/[ 中定期更新 curTime
=34=]ScalaFX,如下:
import model.Clock
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.geometry.Insets
import scalafx.scene.Scene
import scalafx.scene.layout.HBox
import scalafx.scene.text.Text
import scalafx.Includes._
object Main
extends JFXApp {
val clock = new Text()
// Clock.curTime is now a StringProperty, which we bind to clock's text. Since clock is
// created lazily, it starts the timer event, so we do not need startClock either.
clock.text <== Clock.curTime
// Create the stage & scene.
stage = new PrimaryStage {
title = "ScalaFX clock"
scene = new Scene {
content = new HBox {
padding = Insets(50, 80, 50, 80)
children = clock
}
}
}
}
在Clock.scala
中:
import java.util.Date
import java.text.SimpleDateFormat
import scalafx.animation.PauseTransition
import scalafx.application.Platform
import scalafx.beans.property.StringProperty
import scalafx.util.Duration
import scalafx.Includes._
// Object should be constructed lazily on the JFX App Thread. Verify that...
object Clock {
assert(Platform.isFxApplicationThread)
private val dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss")
val curTime = new StringProperty(getDate())
// Update the curTime property every second, using a timer.
// Note: 1,000 ms = 1 sec
val timer = new PauseTransition(Duration(1000))
timer.onFinished = {_ =>
curTime.value = getDate()
timer.playFromStart() // Wait another second, or you can opt to finish instead.
}
// Start the timer.
timer.play()
private def getDate() = dateFormat.format(new Date())
}