Tornadofx: CellFactory updateItem unavailable

Created on 30 Aug 2018  路  14Comments  路  Source: edvin/tornadofx

My case is to make cell color be changed by right mouse click.
I'm trying to write this code in Kotlin + tornadofx. however in setCellFactory there is nothing simillar. How can I correctly rewrite this code?

public void initialize() {
        userIdColumn.setCellFactory(tc -> {
            TableCell<User, String> cell = new TableCell<User, String>() {
                @Override
                protected void updateItem(String item, boolean empty) {
                    super.updateItem(item, empty) ;
                    setText(empty ? null : item);
                }
            };
            cell.setOnMouseClicked(e -> {
                if (! cell.isEmpty()) {
                    String userId = cell.getItem();
                }
            };
        });
    }

All 14 comments

TornadoFX is just an API on top of JavaFX - it never hides the underlying API, so you can write exactly that same code, just with Kotlin syntax.

I tried however it's doesn't work. Is there any method to set custom cell factory?
My code:

class CustomCell: TableCell<SellDepartmentTask, String>(), Callback<TableColumn<SellDepartmentTask, String>, TableCell<SellDepartmentTask, String>> {
    override fun call(param: TableColumn<SellDepartmentTask, String>?): TableCell<SellDepartmentTask, String> {
        println("check")
        return CustomCell()
    }

    override fun updateSelected(selected: Boolean) {
        super.updateSelected(selected)
        if (item == "qwe") {
            textFill = Color.CHOCOLATE
            style = "-fx-background-color: yellow"
        }
        setOnMouseClicked {
            if (it == MouseButton.SECONDARY) {
                style = "-fx-background-color: darkred"
            }
        }
        style = "-fx-background-color: yellow;"

    }
    override fun updateItem(item: String?, empty: Boolean) {
        super.updateItem(item, empty)
        if (item == "qwe") {
            textFill = Color.CHOCOLATE
            style = "-fx-background-color: yellow"
        }
        setOnMouseClicked {
            if (it == MouseButton.SECONDARY) {
                style = "-fx-background-color: darkred"
            }
        }
        style = "-fx-background-color: yellow;"
    }
}

And I tried to call it by:

setCellFactory {
                CustomCell()
            }
            //or
            cellFactory = CustomCell()

like this?

class SomeView : View("Test") {
    val data = listOf("qwe", "fds", "gfa", "dgc").map { SellDepartmentTask(it) }.observable()

    override val root = tableview(data) {
        selectionModel.isCellSelectionEnabled = true
        repeat(10) { _ ->
            column("Test", SellDepartmentTask::name).setCellFactory { CustomCell() }
        }
    }
}

class CustomCell : TableCell<SellDepartmentTask, String>() {

    override fun updateSelected(selected: Boolean) {
        super.updateSelected(selected)
        textFill = if (item == "qwe") Color.CHOCOLATE else Color.BLACK
    }

    override fun updateItem(item: String?, empty: Boolean) {
        super.updateItem(item, empty)
        text = item
        if (item == "qwe") {
            textFill = Color.CHOCOLATE
        }
        background = Color.YELLOW.asBackground()

        setOnMouseClicked {
            if (it.button == MouseButton.SECONDARY && !empty) {
                background = Color.RED.asBackground()
            }
        }
    }
}

The idiomatic TornadoFX approach to this would be to use a CellFragment though :)

code above doesn't work...

No, it doesn't, you're breaking the contract for updateItem in several places. Your issue was about the ability to use CellFactory updateItem, and as you can see that works :) You still need to read up on the requirements for creating a custom cell factory, or use a CellFragment instead.

I never thought that coloring cells will be so difficult to me =C I'm trying to color full row(I thought that it will be a bit easier). Can I color the full row with CellFragment?

Yeah, that's a little involved in JavaFX unfortunately. I think you should create a row factory instead and set the color based on the item state. I don't have an example for you right now, but you'll be able to find JavaFX based examples for this.

Yes, I'm trying to use rowFactory for now by rewriting this code - https://stackoverflow.com/questions/44819807/how-to-change-tableview-row-color-when-some-conditions-are-valid-javafx . How ever it doesn't work for me too =C For now I'm trying to simplify my code and trying to make it change by button click:

testButton.setOnAction {
            testTableView.setRowFactory { _ ->
                val row = TableRow<SellDepartmentTask>()
                row.background = Color.ALICEBLUE.asBackground()
                row
            }
        }

Don't forget about CSS when styling TableViews. This post shows how different styles are applied to add/even rows and to selected rows.

https://courses.bekwam.net/~walkerro/bkcourse_tornadofx_style_tableview.html

This post has a .kt file referenced at the bottom with a more advanced application of TableView styling.

https://courses.bekwam.net/public_tutorials/bkcourse_tornadofx_dragfetchapp.html

Perfect, @bekwam !

Just for completeness, here is an extremely dirty way to set make clicked rows green:

                setRowFactory { _ ->
                    object : TableRow<YourItem>() {
                        init {
                            setOnMouseClicked {
                                style {
                                    backgroundColor += Color.GREEN
                                }
                            }
                        }
                    }
                }

Here's another snippet with a slightly different syntax from Edvin's example that sets a background at the end of the updateItem(). After you get something going, you'll want to replace the setter calls with Type Safe CSS.

    tableview(c.data) {

        column("Date", Commit::commitDateProperty) {
            converter(LocalDateTimeStringConverter())
        }
        column("Committer", Commit::committerProperty)
        column("Log", Commit::logEntryProperty)

        rowFactory = Callback {
            object : TableRow<Commit>() {
                override fun updateItem(item: Commit?, empty: Boolean) {
                    super.updateItem(item, empty)
                    // set your logic and style-mapping here
                    background = Color.YELLOW.asBackground()
                }
            }
        }

        vgrow = Priority.ALWAYS
    }

Thanks for help. I got some problems with coloring text in the row. But I found solution (if anyone will need it):

class MyStyles: Stylesheet() {
    companion object { val notIdentified by csspseudoclass() }

    init {
        notIdentified {
            cell {
                textFill = Color.BLACK
            }
        }
    }
}

Great thanks for helping!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

arslancharyev31 picture arslancharyev31  路  7Comments

Leo-Thura picture Leo-Thura  路  6Comments

ThraaxSession picture ThraaxSession  路  3Comments

eibens picture eibens  路  4Comments

jagiellonczyk14 picture jagiellonczyk14  路  6Comments