【问题标题】:Is there a way to update FX-Properties from another Thread without Platform.runLater() in kotlin?有没有办法在 kotlin 中没有 Platform.runLater() 的情况下从另一个线程更新 FX 属性?
【发布时间】:2019-10-04 20:55:44
【问题描述】:

我尝试学习 kotlin,但 TornadoFX 线程有问题。

在 JavaFX 中,我可以在另一个线程中更新 observable 属性,并且更新将发生在视图中,而无需使用“Platform.runLater()”触发

更新

我对 JFX 中的线程安全的所有假设都是错误的!

仅使用 Platform.runLater()、Tasks 或 Animationtimer 更新绑定到 UI 线程的 UI 元素或属性,切勿在没有 Platform.runLater() 的情况下从外部更新。

虽然您应该谨慎使用 Platform.runLater(),因为您无法控制何时将什么添加到 UI 线程,这可能会引起一些麻烦。

以下是我的误解

这是 在 JavaFX 中工作正常 工作但也是错误的


   @Fxml
   ProgressBar progress;

   @Fxml
   public void initialize(){
        DoubleProperty prop = new SimpleDoubleProperty(0);
        progress.progressProperty().bind(prop);
        ExecutorService ex = Executors.newSingleThreadExector();
        ex.execute(()->{
          while(true){
             Thread.sleep(2000);
             prop.set(prop.get()+0.1);

       }
   }


   }


本质上是相同的代码,但在 Kotlin 中。它不起作用并抛出异常:

不在 FX 应用程序线程上; currentThread = Thread-3 TornadoFX


class test : View() {
    override val root: BorderPane by fxml("/views/primary.fxml")

    val counter = SimpleDoubleProperty()
    val progress: ProgressBar by fxid()

    init {
         thread{
                while(true){
                 Thread.sleep(2000)
                 counter.value += 0.1
                }
             }

        progress.bind(counter)


    }



}


我希望他们会以同样的方式工作。 我可以用“Platform.runLater(()->...)”修复它,但是当它已经观察到属性时,我不想在 UI 线程中排队所有东西。 我认为这是将某些东西绑定到 UI 元素的可能性的全部目的。

是我使用了错误的属性和绑定还是 TornadoFX 问题

【问题讨论】:

  • 不,它在 fx 中不能正常工作,即使它不会立即抛出错误和定时炸弹。我们不得从 fx 线程更新场景图中节点的属性,没有例外,没有办法绕过 周期
  • 您所说的“在 JavaFX 中工作正常”是错误的。当属性绑定到 UI 元素时,您不应在另一个线程中更新属性。这将触发来自另一个线程的绑定 UI 元素的更新,这可能会导致内部 JavaFX 系统实现中的竞争条件和错误。所以你不应该那样做。绑定到 UI 的属性只能在 JavaFX 应用程序线程上更新。
  • 为什么你认为来自 Observables 的通知是线程安全的?它是一个接口,我在其文档中看不到任何强制其实现保证这样的东西的东西。或者它是特定于 kotlin 绑定的东西?
  • 竞态条件是由一个线程更新状态而FX线程读取状态引起的。没有适当的同步,因此不能保证 FX 线程看到正确的状态。这会导致未定义的行为。不,正如我已经提到的,Observable 的核心实现都不是线程安全的。不过,我对 TornadoFX 并不太熟悉,所以它可能会在这方面有所补充。
  • 感谢您聆听并进行必要的研究 - 这就是我们所有人最有效地学习的方式:)

标签: java multithreading javafx kotlin tornadofx


【解决方案1】:

我发现了问题。 我在 UI 元素 (View()) 中生成了属性。 FX-UI 中的属性绑定到 UI 线程。

我只需要生成确保我要绑定的属性在 UI 线程之外

这是一种避免“runLater()”的正确方法

object TestThread{
    val property = SimpleDoubleProperty()
    val elapsedSeconds = SimpleLongProperty(0);
    init{
        println("start thread")
        val timer = object : AnimationTimer() {
            override fun handle(now: Long){
                if((now - elapsedSeconds.value)> 100000000){
                    property.value+=0.01
                    elapsedSeconds.value = now
                }

            }
        }
        timer.start()

    }
}

class HelloWorld : View() {
    exception  
   thread

    override val root: BorderPane by fxml("/views/primary.fxml")

    val counter = SimpleDoubleProperty()
    val pro = ProgressBar()


    init {


        root.right{
            add(pro)
        }
        // Now  bind the Property from THE ANIMATION to the UI-element wich
        // wich Observes the changes of the Property with no problem at all
        val t = TestThread
        pro.bind(t.property);
        incr.bind(counter)


    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-16
    • 1970-01-01
    • 2020-01-28
    • 2012-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多