Missing implicit conversions from Property to ObservableValue
The implicit conversion from scalafx.beans.property.IntProperty to scalafx.beans.values.ObservableValue[Int, Int] is missing. This implicit conversion works for String and generic types, but not for primitive types such as Int, Long, Double.
A minimal example to show this issue
1 import scalafx.beans.property._
2 import scalafx.scene.control._
3
4 object ConversionIssue extends App {
5
6 class Person(_name: String, _age: Int) {
7 val name = new StringProperty(this, "name", _name)
8 val age = new IntegerProperty(this, "age", _age)
9 }
10
11 val nameColumn = new TableColumn[Person, String] {
12 cellValueFactory = { _.value.name }
13 }
14
15 val ageColumn = new TableColumn[Person, Int] {
16 cellValueFactory = { _.value.age }
17 }
18
19 }
Line 12 is okay, but line 16 fails with the following error:
Error: type mismatch; found : scalafx.beans.property.IntegerProperty required: scalafx.beans.value.ObservableValue[Int,Int] cellValueFactory = { _.value.age } ^
A workaround here is to define age as an ObjectProperty[Int]:
val age = new ObjectProperty[Int](this, "age", _age)
Can this be fixes at some point, please?
I got similar problem here, not for primary types, but for IntegerProperty:
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.beans.property.{IntegerProperty, StringProperty}
import scalafx.collections.ObservableBuffer
import scalafx.scene.Scene
import scalafx.scene.control.TableColumn._
import scalafx.scene.control.{TableColumn, TableView}
object SimpleTableApp extends JFXApp {
case class Person(name: StringProperty, age: IntegerProperty)
val characters = ObservableBuffer[Person](
Person(StringProperty("Peggy"), IntegerProperty(20)),
Person(StringProperty("Rocky"), IntegerProperty(30))
)
stage = new PrimaryStage {
title = "Simple Table View"
scene = new Scene {
content = new TableView[Person](characters) {
columns ++= List(
new TableColumn[Person, String] {
text = "Name"
cellValueFactory_=(_.value.name)
prefWidth = 180
},
new TableColumn[Person, Integer]() {
text = "Age"
cellValueFactory_=(_.value.age) . // failed to compile
prefWidth = 180
}
)
}
}
}
}
Compilation error:
Error:(33, 40) type mismatch;
found : scalafx.beans.property.IntegerProperty
required: scalafx.beans.value.ObservableValue[Integer,Integer]
cellValueFactory_=(_.value.age)
The type of IntegerProperty is ObservableValue[Integer,Number], which is not a subtype of ObservableValue[Integer,Integer]
Any suggestions how to fix this?
I have the same issue but with a LongProperty. Casting with .asInstanceOf[ObservableValue[Long, Long]] works but it’s not pretty.
Basically, from what I understand, this issue comes from the fact that Java’s Double, Integer, Long extends Number but Scala equivalent don’t.
And because JavaFX uses this heritage heavily (DoubleProperty, IntegerProperty, LongProperty all implements Property[Number], same for DoubleBinding, etc. with Binding[Number]), ScalaFX had to workaround this by using two generic types for Property, one for ScalaFX and one for JavaFX, which are always the same except for Number like DoubleProperty, IntProperty, LongProperty which use their true type for ScalaFX and Number for JavaFX giving Property[Long,Number] for instance.
It works quite well but in TableColumn.cellValueFactory, we need the TableColumn second type which is ScalaFX type (like Long in new TableColumn[Person, Long]()) to match the JavaFX type of the Property. And this can’t work for the number Properties as explained before.
One solution (the simplest I think but also the most limitating) would be to not use ScalaFX property type in cellValueFactory but the JavaFX type instead like in the following signature:
def cellValueFactory: ObjectProperty[TableColumn.CellDataFeatures[S, J] => ObservableValue[?, J]]
allowing to have column using Number like TableColumn[X, Number] but not TableColumn[X, Long] for instance.
A second one, is to define auto-conversion like
given Conversion[LongProperty, ObservableValue[Long, Long]] = _.asInstanceOf[ObservableValue[Long, Long]]
for all numbers type, property and binding. It is what I currently use but I feel uncomfortable with it.
Another one, would be to reimplement DoubleProperty, IntegerProperty, LongProperty in ScalaFX with ObjectProperty[] instead, drop the double property types and left the Number’s Property to JavaFX. I have the feeling it would be the cleanest solution but I may be wrong.
And finally, the fourth solution I see would be to use Java type (java.lang.Double, etc.) in ScalaFX properties. But I’m not sure if it would be a good idea, it might cause a lot’s of issue afterward.
What do you think?