Search code examples
javajavafxkotlintornadofx

Change TornadoFX TableView row background color while still highlighting selected rows


I have a TableView in a TornadoFX application. This TableView shows a list of tests and their status (not started, started, pass, fail). I want the rows of passed tests to be green, and the rows of failed tests to be red. I have gotten the rows to be the correct colors but when I select a row in the table, it is no longer highlighted.

How do I change this formatting to both highlight the selected rows and color the rows to reflect whether that test has passed or failed?

tableview = tableview(tests) {
    readonlyColumn("Test Name", Test::fileName)
    column("Test Execution Status", Test::statusProperty).cellFormat {
        text = it.toString()
        if (it == TestStatus.PASS)
            this.tableRow.style(append = true) { backgroundColor += c("#4CAF50", .5) }
        else if (it == TestStatus.FAIL)
            this.tableRow.style(append = true) { backgroundColor += c("#FF5722", .5) }
    }

    columnResizePolicy = SmartResize.POLICY
    vgrow = Priority.ALWAYS
    selectionModel.selectionMode = SelectionMode.MULTIPLE
    bindSelected(lastSelectedTestInTable)
}

Solution

  • I'm not an expert. I don't know if there is a way to answer your question using your exact method (using inlinecss and setting a backgroundColor without affecting selected row backgroundColor). My solution uses a StyleSheet and set a independent backgroundColor for the selected status of the row.

    class Style : Stylesheet() {
        companion object {
            val pass by cssclass()
            val fail by cssclass()
        }
        init {
            pass{
                backgroundColor += c("#4CAF50", .5)
                and(selected){
                    backgroundColor += c("#0096C9", .5)
                }
            }
            fail{
                backgroundColor += c("#FF5722", .5)
                and(selected){
                    backgroundColor += c("#0096C9", .5)
                }
            }
        }
    }
    

    Now you use the rules "pass" and "fail". Instead of:

    this.tableRow.style(append = true) { backgroundColor += c("#4CAF50", .5) }
    

    You use:

    this.tableRow.addClass(Style.pass)
    

    Instead of:

    this.tableRow.style(append = true) { backgroundColor += c("#FF5722", .5) }
    

    You use:

    this.tableRow.addClass(Style.fail)
    

    Remember you need to add Style::class to your application constructor.

    Edit:

    Using toggleClass as Edvin Syse suggested. instead of:

    column("Test Execution Status", Test::statusProperty).cellFormat {
        text = it.toString()
        if (it == TestStatus.PASS)
            this.tableRow.addClass(Style.pass)
        else if (it == TestStatus.FAIL)
            this.tableRow.addClass(Style.fail)
    }
    

    You use:

    column("Test Execution Status", Test::statusProperty).cellFormat {
        text = it.toString()
        this.tableRow.toggleClass(Style.fail,it == TestStatus.FAIL)
        this.tableRow.toggleClass(Style.pass,it == TestStatus.PASS)     
    }