scalafx and TableView: how do I change slectionModel and focusModel?

234 views Asked by At

I want to use a TableView in scalafx to have a nice table in my GUI where the user can see and input data. There are some nice methods in the classes TableViewSelectionModel and TableViewFocusModel that I would like to use, like for example selectionMode, selectedCells and selectBelowCell from TableViewSelectionModel or focus(pos), focusedCell and focusBelowCell from TableViewFocusModel.

I have the following example, that comes mainly from a YouTube-video from Mark Lewis (who makes excellent learning videos for scala and scalafx by the way, but doesn't cover this topic):

import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.beans.property.{ObjectProperty, StringProperty}
import scalafx.collections.ObservableBuffer
import scalafx.scene.Scene
import scalafx.scene.control.cell.TextFieldTableCell
import scalafx.scene.control.{TableColumn, TableView}
import scalafx.util.converter.DefaultStringConverter

object Main extends JFXApp {

  case class Student(name: String, test1: Int, test2: Int)

  val data = new ObservableBuffer[Student]()
  data ++= List(Student("Jane Doe", 99, 93), Student("John Doe", 73, 88), Student("Bob Builder", 85, 91))

  stage = new JFXApp.PrimaryStage {
    title = "Test for Table View"
    resizable = true
    width = 1000
    height = 800

    val table: TableView[Student] = new TableView[Student](data) {
      editable = true
      //selectionModel = TableView.TableViewSelectionModel[Tables.Student] ???
      //focusModel = TableView.TableViewFocusModel[Tables.Student] ???
    }

    println("selection model: " + table.selectionModel)
    println("focus model: " + table.focusModel)

    val col1: TableColumn[Student, String] = new TableColumn[Student, String] {
      text = "Name"
      editable = true
      cellValueFactory = { cdf: TableColumn.CellDataFeatures[Student, String] => StringProperty(cdf.value.name) }
      cellFactory = (_: TableColumn[Student, String]) => new TextFieldTableCell[Student, String](new DefaultStringConverter())
    }

    val col2: TableColumn[Student, Int] = new TableColumn[Student, Int] {
      text = "Test 1"
      editable = true
      cellValueFactory = { cdf => ObjectProperty(cdf.value.test1) }

    }

    val col3: TableColumn[Student, Int] = new TableColumn[Student, Int] {
      text = "Test 2"
      editable = true
      cellValueFactory = { cdf => ObjectProperty(cdf.value.test2) }

    }
    val col4: TableColumn[Student, Double] = new TableColumn[Student, Double] {
      text = "Average"
      cellValueFactory = { cdf => ObjectProperty((cdf.value.test1 + cdf.value.test2) / 2.0) }
    }

    val col5: TableColumn[Student, String] = new TableColumn[Student, String] {
      text = "Test-Input"
      editable = true
      cellFactory = (_: TableColumn[Student, String]) => { new TextFieldTableCell[Student, String](new DefaultStringConverter())

      }

    }

    table.columns ++= List(col1, col2, col3, col4, col5)


    scene = new Scene {
      root = table
    }
  }
}

My problem is that I don't know java or javaFX. I tried to get the information from the javaFX doc, but that was not really helpful. For example, javaFX has a method for tables .setSelectionMode(SelectionMode.MULTIPLE); that sets the selection mode, but how do I do this in scalafx?

It would help me, if someone could modify the above code, so that single cells are selected and not whole rows. I am pretty sure from there I can figure out the rest on my own.

P.S.: I compiled the above code with sbt version 1.2.8, and my build.sbt file was:

name := "TestTableView"
scalaVersion := "2.13.5"
// Scala FX
libraryDependencies += "org.scalafx" %% "scalafx" % "15.0.1-R21"
libraryDependencies += "org.scala-lang.modules" %% "scala-xml" % "1.2.0"
libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.3"
fork := true
// Tell Javac and scalac for which jvm it has to build (not really necessary)
javacOptions ++= Seq("-source", "1.8", "-target", "1.8")
scalacOptions += "-target:jvm-1.8"
scalacOptions += "-feature"
1

There are 1 answers

0
Michael W. On BEST ANSWER

With the problem of wrong highlighting out of the way, the solution is simple. Just for reference, here is the above code modified with all the asked Options for TableView:

import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.beans.property.{ObjectProperty, StringProperty}
import scalafx.collections.ObservableBuffer
import scalafx.scene.Scene
import scalafx.scene.control.SelectionMode.Multiple
import scalafx.scene.control.cell.TextFieldTableCell
import scalafx.scene.control.{TableColumn, TableView}
import scalafx.util.converter.DefaultStringConverter

object Main extends JFXApp {

  case class Student(name: String, test1: Int, test2: Int)

  val data = new ObservableBuffer[Student]()
  data ++= List(Student("Jane Doe", 99, 93), Student("John Doe", 73, 88), Student("Bob Builder", 85, 91))

  stage = new JFXApp.PrimaryStage {
    title = "Test for Table View"
    resizable = true
    width = 1000
    height = 800

    val table: TableView[Student] = new TableView[Student](data) {
      editable = true
      selectionModel.apply.cellSelectionEnabled = true
      selectionModel().selectionMode = Multiple  //Choose between Single and Multiple
      selectionModel.apply.selectedItem.onChange {
        println("Selected" + selectionModel.apply.getSelectedItem)
        println("Selected row-Index: " + selectionModel.apply.selectedIndex.value)
        println("Selected cells: " + table.selectionModel().selectedCells)
        println("Focused Cell: " + table.focusModel().focusedCell)
      }
    }

    val col1: TableColumn[Student, String] = new TableColumn[Student, String] {
      text = "Name"
      editable = true
      cellValueFactory = { cdf: TableColumn.CellDataFeatures[Student, String] => StringProperty(cdf.value.name) }
      cellFactory = (_: TableColumn[Student, String]) => new TextFieldTableCell[Student, String](new DefaultStringConverter())
    }

    val col2: TableColumn[Student, Int] = new TableColumn[Student, Int] {
      text = "Test 1"
      editable = true
      cellValueFactory = { cdf: TableColumn.CellDataFeatures[Student, Int] => ObjectProperty(cdf.value.test1) }
      //cellFactory = (_: TableColumn[Student, String]) => new TextFieldTableCell[Student, String](new DefaultStringConverter())
    }

    val col3: TableColumn[Student, Int] = new TableColumn[Student, Int] {
      text = "Test 2"
      editable = true
      cellValueFactory = { cdf => ObjectProperty(cdf.value.test2) }

    }
    val col4: TableColumn[Student, Double] = new TableColumn[Student, Double] {
      text = "Average"
      cellValueFactory = { cdf => ObjectProperty((cdf.value.test1 + cdf.value.test2) / 2.0) }
    }

    val col5: TableColumn[Student, String] = new TableColumn[Student, String] {
      text = "Test-Input"
      editable = true
      cellFactory = (_: TableColumn[Student, String]) => {
        new TextFieldTableCell[Student, String](new DefaultStringConverter())
      }
    }
    table.columns ++= List(col1, col2, col3, col4, col5)

    table.requestFocus()
    table.selectionModel().select(1, col1)          //Select 2'nd (count starts at 0) cell in col2, that is Test1
    table.focusModel().focus(1, col1)               //Set focus on
    table.edit(1, col1)                             //wander what this is doing
    table.selectionModel().selectBelowCell()        //Selects the cell below
    table.focusModel().focusBelowCell()             //Focuses on the cell below

    scene = new Scene {
      root = table
    }
  }