ScalaFX: ListView with CellFactory

I had a bit hard time to get ScalaFX to display a list of items in a scrollable space, and each item can be clicked. I use this in TLCockpit to display the list of documentation files in a TeX Live package, and open it directly from the application. Unfortunately there is not a huge amount of examples using ScalaFX out there in the web, so it took me a bit. My first try was using a VBox with various Labels in there, but this is not scrollable.

In other areas I have used TreeTableView, so in this case using ListView should be fine. What I finally came up is the following code:

import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.collections.ObservableBuffer
import scalafx.geometry.Orientation
import scalafx.scene.control.{ListCell, ListView}
import scalafx.scene.input.MouseEvent
import scalafx.scene.{Cursor, Scene}
import scalafx.scene.paint.Color
import scalafx.Includes._

object ApplicationMain extends JFXApp {

  val SomeStrings: Seq[String] = Seq("Hello", "World", "Enjoy")

  stage = new PrimaryStage {
    title = "ListViewExample"
    scene = new Scene {
      root = {
        new ListView[String] {
          orientation = Orientation.Vertical
          cellFactory = {
            p => {
              val cell = new ListCell[String]
              cell.textFill = Color.Blue
              cell.cursor = Cursor.Hand
              cell.item.onChange { (_, _, str) => cell.text = str }
              cell.onMouseClicked = { me: MouseEvent => println("Do something with " + cell.text.value) }
              cell
            }
          }
          items = ObservableBuffer(SomeStrings)
        }
      }
    }
  }
}

Some comments to the code, at least as far I understand it:

  • line 9: Importing scalafx.Includes._ seems to simplify some things, in particular the event handler routines can be written more straight forward.
  • line 20: Many more properties can be set here, for example the preferred height and max height, both of which I am using.
  • line 23: In my case a ListCell was enough for my needs (changing color, cursor, and allowing for mouse clicks), but if one needs something more complicated here it is bst to create an arbitrary object and asign it to the graphic field.
  • line 26: The essential part to actually fill the cells is the routine cell.item.onChange, which takes three arguments of which the last is the new value. It is used to update the cell text.
  • line 31: Last but not least one needs to assign some Observable to the items, in this case I use ObservableBuffer around the lost of strings.

Once managed, it doesn’t look so complicated, but took me some time.

1 Response

Leave a Reply

Your email address will not be published. Required fields are marked *