我有一个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版本和/或告诉我为什么代码永不返回?

最佳答案

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

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,因此ScalaFX Platform.runLater很高兴。

更新:

如果您想从Platform.runLater中获取一个值,那么您在问题中建议的方法通常会很好。但是,您要确保不阻止FX Application Thread。如果您在FX Application Thread上调用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()
}

07-24 19:05