【问题标题】:How can I get a value from a the ScalaFX thread?如何从 ScalaFX 线程中获取值?
【发布时间】:2014-05-01 05:28:43
【问题描述】:

我有一个myNode: scalafx.scene.Node,我想将其转换为位图,以便将其保存到磁盘,将其与其他位图进行比较等。我认为将其转换为scalafx.scene.image.WritableImage 的正确代码是

val writableImg = new Scene { root = new Group(myNode) }.snapshot(null)

然后我应该可以把它变成java.awt.image.RenderedImage

val renderedImg = SwingFXUtils.fromFXImage(writableImg, null)

您可能已经意识到,问题是我必须运行代码才能在 ScalaFX 线程上获取 wrImg。有一个问题here 解释了如何返回一个值,但我没有运气将它翻译成 Scala。我试过这个:

lazy val writableImg: WritableImage = {
  val wrImg = new FutureTask(new Callable[WritableImage]() {
    override def call(): WritableImage = {
      new Scene { root = new Group(myNode) }.snapshot(null)
    }
  })
  Platform.runLater(wrImg)
  wrImg.get()
}

但代码只是挂起并且永远不会完成。谁能提供一个惯用的 Scala 版本和/或告诉我为什么代码永远不会返回?

【问题讨论】:

  • 好吧,这很奇怪...myNode 依赖于lazy val。我取出了lazy 部分,现在一切正常。这是意料之中的,还是我在处理lazy vals 的方式上遇到了错误?

标签: multithreading scala javafx-2 future scalafx


【解决方案1】:

如果您只想将图像保存到磁盘,您可以简单地在同一个线程上执行,避免传递图像的复杂性。这样的事情会起作用:

Platform.runLater {
  val node = new Circle {
    centerX = 200
    centerY = 200
    radius = 50
    stroke = Color.BROWN
    strokeWidth = 2
    fill = Color.DARKKHAKI
  }
  val jfxImage = node.snapshot(new SnapshotParameters(), null)
  val bufferedImage = SwingFXUtils.fromFXImage(jfxImage, null)
  val file = new File("./snapshot.png")
  println("Writing snapshot to: " + file.getAbsolutePath)
  javax.imageio.ImageIO.write(bufferedImage, "png", file)
  ()
}

空的()有闭包返回Unit,所以ScalaFXPlatform.runLater很高兴。

更新

如果您想从Platform.runLater 获得值,您在问题中建议的方法通常应该没问题。但是,您要确保不阻塞 FX 应用程序线程。如果您在 FX 应用程序线程上调用 Platform.runLater,您将被锁定,所以您可能想要这样的东西

def makeSnapshot() = myNode.snapshot(new SnapshotParameters(), null)

val writableImg = if (Platform.isFxApplicationThread) {
  makeSnapshot()
} else {
  val futureTask = new FutureTask(new Callable[WritableImage]() {
    override def call(): WritableImage = makeSnapshot()
  })
  Platform.runLater(futureTask)
  futureTask.get()
}

【讨论】:

  • 您假设我不需要保存图像以供以后使用,我确实这样做了。在图书馆中,学生应该能够创建图像、基于它创建新图像、显示它并将他们创建的任何图像保存到磁盘。重点是能够传递图像。
  • 我没有意识到不能在 FX 应用程序线程中使用 Platform.runLater() 的微妙之处。谢谢你的洞察力!!!我将使用Platform.isFxApplicationThread 守卫,看看是否有帮助。这也可能是我悬赏的 SBT 问题的答案。
猜你喜欢
  • 1970-01-01
  • 2018-11-26
  • 2020-11-09
  • 1970-01-01
  • 2011-03-18
  • 2011-10-17
  • 2018-04-15
相关资源
最近更新 更多