Add item to a TableView that the user sorted by a certain column while respecting the sort

34 Views Asked by At

I have a TableView that the user can sort by any of its columns. Depending on other events in the app, I want to add data to the TableView. However, when I add the data, the new row always appears on the bottom of the TableView, even though it should appear somewhere else according to the sort order.

My question is, therefore, how I can add data to the TableView such that the TableView is still sorted correctly according to the column that was selected by the user.

Here's the relevant code controlling the TableView:

@FXML
private lateinit var tableColumnMeasurementLogBib: TableColumn<LogEntry, Int>

@FXML
private lateinit var tableColumnMeasurementLogResult: TableColumn<LogEntry, Double>

@FXML
private lateinit var tableColumnMeasurementLogTimestamp: TableColumn<LogEntry, LocalDateTime>

@FXML
private lateinit var tableViewMeasurementLog: TableView<LogEntry>

private val logEntries = FXCollections.observableArrayList<LogEntry>()

private fun setupMeasurementLog() {
    tableViewMeasurementLog.items = logEntries
    
    tableColumnMeasurementLogTimestamp.cellValueFactory = PropertyValueFactory(LogEntry::timestamp.name)
    tableColumnMeasurementLogResult.cellValueFactory = PropertyValueFactory(LogEntry::result.name)
    tableColumnMeasurementLogBib.cellValueFactory = PropertyValueFactory(LogEntry::athleteId.name)

    tableColumnMeasurementLogTimestamp.setCellFactory {
        object : TableCell<LogEntry, LocalDateTime>() {
            override fun updateItem(item: LocalDateTime?, empty: Boolean) {
                super.updateItem(item, empty)
                if (empty || item == null) {
                    text = ""
                    return
                }

                text = measurementLogDateTimeFormatter.format(item)
            }
        }
    }
}

private fun addDataToLog(athleteId: Int, result: Double, timestamp: LocalDateTime) {
    logEntries.add(LogEntry(athleteId, result, timestamp))
}

data class LogEntry(val athleteId: Int, val result: Double, val timestamp: LocalDateTime)

Steps to reproduce:

  1. Call addDataToLog with some values.
  2. In the UI, click on any of the column headers to sort the table by that column.
  3. Call addDataToLog again.
  4. The new data row will always appear at the bottom, no matter where it should actually appear (according to the sorted column).
1

There are 1 best solutions below

0
vatbub On

Turns out reading the JavaDocs would have been of great help here. Simply wrapping the list in a SortedList like so does the job:

val sortedLogs = SortedList(logEntries)
tableViewMeasurementLog.items = sortedLogs
sortedLogs.comparatorProperty().bind(tableViewMeasurementLog.comparatorProperty())