代码之家  ›  专栏  ›  技术社区  ›  Oleg

ScalaFX。实时绑定

  •  2
  • Oleg  · 技术社区  · 7 年前

    我有一个简单的UI窗口,只有一个文本节点,它显示当前时间并绑定到模型:

    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是否更改?

    对不起我的英语:(

    1 回复  |  直到 7 年前
        1
  •  2
  •   Mike Allen    7 年前

    问题是 Clock.curTime 它只是一个变量,其值会定期更新-它不是一个观察到的属性,因此当它被更改时不会发生任何事情。特别是,这个变量和您的 Text 元素的内容

    您所做的是初始化 StringProperty 具有该值-但由于属性本身从未更新,因此标签也不会更新。我想你想做的是 curTime StringProperty 而不仅仅是一个 String . 现在,无论何时更改该属性的值 文本 元素的值将相应更改。

    您应该注意,与 JavaFX / ScalaFX公司 只能发生在 JavaFX应用程序线程 ,因此如果您尝试更新 柯蒂姆 从另一个线程,你会遇到问题。实现这一点的一种方法是传递实际更新的代码 柯蒂姆 Platform.runLater .

    然而,更简单的方法是使用定时 ScalaFX公司 要更新的事件 柯蒂姆 从内部定期 / 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())
    }