Usability of JavaFX Properties outside the scope of the GUI view

前端 未结 3 1998
忘掉有多难
忘掉有多难 2020-12-05 19:27

After working some while with JavaFX (Java8) I had found the concept of Properties very useful, allowing to use bean compliant variables to be bound to update on changes usi

3条回答
  •  一整个雨季
    2020-12-05 19:58

    I ran into this today and it sure was helpful that someone pointed to threads. The errors caused by this can be insidious.

    I'm using this solution extensively. You can't bindBidirectional with a ThreadSafeObjectProperty, but you can bind to an FX Property and update it using ThreadSafePropertySetter.

    The setters return a Future. Which can be used to control the race conditions caused by Platform.runLater.

    It's in Scala:

    class SafePublishProperty[T](init: T) {
      val writable = new ReadOnlyObjectWrapper[T](init)
      def readOnly: ObjectExpression[T] = writable.getReadOnlyProperty
    }
    
    class ThreadSafeBooleanProperty(init: Boolean) {
      protected val property = new ReadOnlyBooleanWrapper(init)
    
      def value: BooleanExpression = property.getReadOnlyProperty
    
      def setValue(value: Boolean): Future[Boolean] = {
        val promise = Promise[Boolean]
        if (Platform.isFxApplicationThread) {
          property.setValue(value)
          promise.success(true)
        }
        else
          try {
            Platform.runLater(() => {
              property.setValue(value)
              promise.success(true)
            })
          } catch {
            case _: IllegalStateException =>
              property.setValue(value)
              promise.success(true)
          }
        promise.future
      }
    }
    
    class ThreadSafeObjectProperty[T](init: T) {
      protected val property = new SafePublishProperty[T](init)
    
      def value: ObjectExpression[T] = property.readOnly
    
      def setValue(value: T): Future[Boolean] = {
        val promise = Promise[Boolean]
        if (Platform.isFxApplicationThread) {
          property.writable.setValue(value)
          promise.success(true)
        }
        else {
          try {
            Platform.runLater(() => {
              property.writable.setValue(value)
              promise.success(true)
            })
          } catch {
            case _: IllegalStateException =>
              property.writable.setValue(value)
              promise.success(true)
          }
        }
        promise.future
      }
    }
    
    object ThreadSafePropertySetter {
      def execute(function: () => Unit): Future[Boolean] = {
        val promise = Promise[Boolean]
        if (Platform.isFxApplicationThread) {
          function.apply()
          promise.success(true)
        }
        else {
          try {
            Platform.runLater(() => {
              function.apply()
              promise.success(true)
            })
          } catch {
            case ex: IllegalStateException =>
              function.apply()
              promise.success(true)
          }
        }
        promise.future
      }
    }
    

    Typical usage:

      class SomeExample {
        private val propertyP = new ThreadSafeBooleanProperty(true)
    
        def property: BooleanExpression = propertyP.value
    
        private class Updater extends Actor {
          override def receive: Receive = {
            case update: Boolean =>
              propertyP.setValue(update)
          }
        }
      }
    

提交回复
热议问题