1

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"
Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Michael W.
  • 182
  • 1
  • 12
  • OK, I just found my problem: I am using IntelliJ IDEA as an IDE, and its highlighting system is not always reliable. If I have a TableView 'table' and I progam: `table.selectionModel.apply.cellSelectionEnabled = true` IntelliJ reports "can not resolve symbol", but the line compiles and runs perfectly fine! That's why I could not find a solution. So this matter is not urgent for me any more. In a few days I will write my own solution to this. – Michael W. Mar 24 '21 at 08:08

1 Answers1

0

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
    }
  }
Michael W.
  • 182
  • 1
  • 12