Custom cells
How to create TableView that displays custom cells containing text and graphics?
To display custom content in TableView
you create TableColumn
and specify what should be displayed
using cellValueFactory
and how it should be deployed using cellFactory
.
Let’s assume that data for each row in the table are represented by instances of a case class Person
:
class Person(firstName_ : String, lastName_ : String, favoriteColor_ : Color) {
val firstName = new StringProperty(this, "firstName", firstName_)
val lastName = new StringProperty(this, "lastName", lastName_)
val favoriteColor = new ObjectProperty(this, "favoriteColor", favoriteColor_)
}
Say, you want to display the first and last name of a person as text, but you want to show the favorite color as a
colored circle. Displaying columns with text is simple, you just create a new column and provide cellValueFactory
that
describes how to extract data from Person
object. TableColumn
knows how to display text:
new TableColumn[Person, String] {
text = "First Name"
// Cell value is loaded from a `Person` object
cellValueFactory = {
_.value.firstName
}
}
Displaying a color circle is not that much more complex, we just need to let the TableColumn
know that
the favoriteColor
should be rendered as a graphic of a specific color. This is done defining custom cellFactory
for
the column. As before, define how to create cell value from Person
object using cellValueFactory
.
ScalaFX 16.0.0-R25 or newer
Here is how this can be done in ScalaFX 16.0.0-R25. Notice that when defining cellFactory
we do not need to create a
new cell (as in older versions of ScalaFX), and we do not need to provide how to render empty cells. All boilerplate
code is created behind the scenes by ScalaFX. We only need to customize cell’s content using a lambda that provides
already created cell and value that needs to be displayed in that cell:
new TableColumn[Person, Color] {
text = "Favorite Color"
// What should be used as the value of the cell
cellValueFactory = _.value.favoriteColor
// How the value should be displayed in the cell
cellFactory = (cell, color) => {
cell.graphic = Circle(fill = color, radius = 8)
}
}
Below is a complete example that will display a table with custom cells:
import scalafx.application.JFXApp3
import scalafx.application.JFXApp3.PrimaryStage
import scalafx.collections.ObservableBuffer
import scalafx.scene.Scene
import scalafx.scene.control.TableColumn._
import scalafx.scene.control.{TableColumn, TableView}
import scalafx.scene.paint.Color
import scalafx.scene.shape.Circle
/** Illustrates use of TableColumn CellFactory to do custom rendering of a TableCell. */
object TableWithCustomCellDemo extends JFXApp3 {
private val characters = ObservableBuffer[Person](
new Person("Peggy", "Sue", "555-6798", Color.Violet),
new Person("Rocky", "Raccoon", "555-6798", Color.GreenYellow),
new Person("Bungalow ", "Bill", "555-9275", Color.DarkSalmon)
)
override def start(): Unit = {
stage = new PrimaryStage {
title = "TableView with custom color cell"
scene = new Scene {
root = new TableView[Person](characters) {
columns ++= Seq(
new TableColumn[Person, String] {
text = "First Name"
cellValueFactory = _.value.firstName
},
new TableColumn[Person, String]() {
text = "Last Name"
cellValueFactory = _.value.lastName
},
new TableColumn[Person, Color] {
text = "Favorite Color"
// What should be used as the value of the cell
cellValueFactory = _.value.favoriteColor
// How the value should be displayed in the cell
cellFactory = (cell, color) => {
cell.graphic = Circle(fill = color, radius = 8)
}
}
)
}
}
}
}
}
You can find the code for this and other examples in scalafx-demos .
ScalaFX 16.0.0-R24 and older
Before 16.0.0-R25 the process of creating a custom cellFactory was a bit more tedious. You needed to create a new
instance of a TableCell
and handle the cases when cell content was empty (or null
).
new TableColumn[Person, Color] {
text = "Favorite Color"
// What should be used as the value of the cell
cellValueFactory = _.value.favoriteColor
// How the value should be displayed in the cell
cellFactory = { _ =>
new TableCell[Person, Color] {
item.onChange { (_, _, newColor) =>
graphic =
if (newColor != null)
Circle(fill = color, radius = 8)
else
null
}
}
}
}
Below is a complete example that will display a table with custom cells:
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.collections.ObservableBuffer
import scalafx.scene.Scene
import scalafx.scene.control.TableColumn._
import scalafx.scene.control.{TableCell, TableColumn, TableView}
import scalafx.scene.paint.Color
import scalafx.scene.shape.Circle
object TableWithCustomCellDemo extends JFXApp {
val characters = ObservableBuffer[Person](
new Person("Peggy", "Sue", Color.Violet),
new Person("Rocky", "Raccoon", Color.GreenYellow),
new Person("Bungalow ", "Bill", Color.DarkSalmon)
)
stage = new PrimaryStage {
title = "TableView with custom color cell"
scene = new Scene {
content = new TableView[Person](characters) {
columns ++= Seq(
new TableColumn[Person, String] {
text = "First Name"
cellValueFactory = {
_.value.firstName
}
},
new TableColumn[Person, String]() {
text = "Last Name"
cellValueFactory = {
_.value.lastName
}
},
new TableColumn[Person, Color] {
text = "Favorite Color"
cellValueFactory = {
_.value.favoriteColor
}
// Render the property value when it changes,
// including initial assignment
cellFactory = { _ =>
new TableCell[Person, Color] {
item.onChange { (_, _, newColor) =>
graphic =
if (newColor != null)
new Circle {
fill = newColor
radius = 8
}
else
null
}
}
}
}
)
}
}
}
}