I have a simple scalafx app but I am struggling to get simple mouse interactions working.
I have custom Canvas node class called Square :
case class Square(val index: Int) extends Canvas
I then have a custom GridPane that is filled with squares :
class BoardPane extends GridPane
{
val squares: Array[Square] = (0 to 63).toArray.map(index => Square(index))
(0 to 63).foreach(index => add(squares(index), index%8, 7-index/8))
}
When I try to get the pick result from a mouse event :
class PlayableBoardPane extends BoardPane
{
onMouseDragged = (event => {
val node: Option[Node] = event.pickResult.intersectedNode
...
})
}
The intersected node is not a Square but a "scalafx.scene.LowerPriorityIncludes$$anon$4" (with implicit conversion)
Is there a way I can map this node back to my squares?
Without that I fail to see how to even use node picking with subclassed nodes at all.
Keep in mind that ScalaFX helps you build a JavaFX application - the underlaying structures are JavaFX. That is, when you build a scene graph in ScalaFX it is composed of JavaFX objects.
For that reason, ScalaFX application should be build trough composition not inheritance. When you simply inherit from a ScalaFX wrapper, like in your example:
case class Square(val index: Int) extends Canvas
it is extending a wrapper not the actual JavaFX class. When you build a scene graph and then examine it through picking you will see JavaFX objects not the wrappers you created. You can deal with that is various ways. A simple one is to set userData
that is passed to underlying JavaFX object. I complete example from fragments you posed would be like this:
import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.scene.Scene
import scalafx.scene.canvas.Canvas
import scalafx.scene.layout.GridPane
object PickResultWithSubclassedNodes extends JFXApp {
case class Square(index: Int) extends Canvas {
height = 25
width = 25
userData = index.toString
}
class BoardPane extends GridPane {
val squares: Array[Square] = (0 to 63).toArray.map(index => Square(index))
(0 to 63).foreach(index => add(squares(index), index % 8, 7 - index / 8))
}
class PlayableBoardPane extends BoardPane {
onMouseReleased = (event => {
val node = event.pickResult.intersectedNode
node match {
case Some(n) => println("Picked: " + n.userData)
case None =>
}
})
}
stage = new PrimaryStage {
title = "Blocking"
scene = new Scene {
root = new PlayableBoardPane()
}
}
}
Clicking on the window will produce output like this:
Picked: 40
Picked: 42
Picked: 17
Picked: 36
Picked: 52
Picked: 38
Picked: 27
No issue with unusual implicit classes.