4

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

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

然后我应该能够把它变成一个java.awt.image.RenderedImagewith

val renderedImg = SwingFXUtils.fromFXImage(writableImg, null)

您可能已经意识到,问题是我必须运行代码才能进入wrImgScalaFX 线程。这里有一个问题解释了如何返回一个值,但我没有运气将它翻译成 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 版本和/或告诉我为什么代码永远不会返回?

4

1 回答 1

2

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

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 应用程序线程。如果您调用Platform.runLaterFX 应用程序线程,您将被锁定,因此您可能想要这样的东西

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()
}
于 2014-03-25T00:36:34.813 回答