Javafx: TableView change row color based on column value
Asked Answered
P

4

10

I have the following piece of code to update both the color of a column cell and its corresponding row:

    calltypel.setCellFactory(column -> {
        return new TableCell<CallLogs, String>() {
            @Override
            protected void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);

                setText(empty ? "" : getItem().toString());
                setGraphic(null);

                TableRow currentRow = getTableRow();

                //This doesn't work
                if(item.equals("a")){
                    item.setTextFill(Color.RED);
                    currentRow.setTextFill(Color.PINK);
                    }
                else{
                    item.setTextFill(Color.GREEN);
                    currentRow.setTextFill(Color.BLUE);
                }

            }
        };
    });

The code segment of 'if' condition doesn't work. I am unable to identify the correct references to objects and also what is the best way to do this.

Thanks!

Principally answered 17/6, 2015 at 11:5 Comment(3)
item is String so you cannot do item.setTextFill(). Instead call this.setTextFill(). What happens if one cell is "a" and another not, what will the color of the row?Telangiectasis
In both conditions, the colors are different. But the row coloring doesn't work. Infact, item.equals doesn't work.Principally
I tried if (!isEmpty()) { this.setTextFill(Color.GREEN); if(item.equals("missed call")) this.setTextFill(Color.RED);} and this works, but this is not the way I wish to write if clause. Also, how to set text color for the entire row?Principally
P
16
private void customiseFactory(TableColumn<CallLogs, String> calltypel) {
    calltypel.setCellFactory(column -> {
        return new TableCell<CallLogs, String>() {
            @Override
            protected void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);

                setText(empty ? "" : getItem().toString());
                setGraphic(null);

                TableRow<CallLogs> currentRow = getTableRow();

                if (!isEmpty()) {

                    if(item.equals("a")) 
                        currentRow.setStyle("-fx-background-color:lightcoral");
                    else
                        currentRow.setStyle("-fx-background-color:lightgreen");
                }
            }
        };
    });
}

This works!

Principally answered 2/7, 2015 at 6:52 Comment(5)
What is calltypel?Septicidal
This will fail when the user hides the column (visibility property)Flipper
This answer is not useful since the type of the variable calltypel is not specified.Alwin
@MateusViccari calltypel should be a TableColumn object.Indisposed
I have table with 30 rows, only 7 visible. Column values are Integer, I want only color row with number 3. But when I scroll up and down (show other rows than those 7), more rows get colored. After some time I can color all rows. @Flipper I need to look for what do you mean.Sherrell
C
14

The correct approach is to use setRowFactory of the Table:

table.setRowFactory(tv -> new TableRow<CustomItem>() {
    @Override
    protected void updateItem(CustomItem item, boolean empty) {
        super.updateItem(item, empty);
        if (item == null || item.getValue() == null)
            setStyle("");
        else if (item.getValue() > 0)
            setStyle("-fx-background-color: #baffba;");
        else if (item.getValue() < 0)
            setStyle("-fx-background-color: #ffd7d1;");
        else
            setStyle("");
    }
});
Crept answered 26/5, 2019 at 1:10 Comment(0)
T
8

I recently did a little research about this subject. With the following code you can change the row color of a TableView based on a column value (I will try to explain it the best I can).

The first thing we have to do is to define the TableView and the Columns of this TableView:

private TableView<Person> personTable;
private TableColumn<Person, String> nameColumn;
private TableColumn<Person, String> lastNameColumn;

The next step is to define the Cell Factory of one of the columns:

nameColumn.setCellFactory(column -> {
    return new TableCell<Person, String>() {
        @Override
        protected void updateItem(String item, boolean empty) {
            super.updateItem(item, empty); //This is mandatory

            if (item == null || empty) { //If the cell is empty
                setText(null);
                setStyle("");
            } else { //If the cell is not empty

                setText(item); //Put the String data in the cell

                //We get here all the info of the Person of this row
                Person auxPerson = getTableView().getItems().get(getIndex());

                // Style all persons wich name is "Edgard"
                if (auxPerson.getName().equals("Edgard")) {
                    setTextFill(Color.RED); //The text in red
                    setStyle("-fx-background-color: yellow"); //The background of the cell in yellow
                } else {
                    //Here I see if the row of this cell is selected or not
                    if(getTableView().getSelectionModel().getSelectedItems().contains(auxPerson))
                        setTextFill(Color.WHITE);
                    else
                        setTextFill(Color.BLACK);
                }
            }
        }
    };
});

The logic of the code: the updateItem() method that we overwrite, it's called automatically when the underlying item changes.

We receive the data item (a String in this case) that has to be rendered. If the item is empty or null (an empty cell for example), we don't apply any style. Otherwise, we format the item, set the text of the cell, and also the colour and the background, depending on the Name of the Person.

If you want to apply this colour of the cell in the other columns of the table, we have to use 'Row Factory' instead of 'Cell Factory', but the logic of the code is similar:

personTable.setRowFactory(row -> new TableRow<Person>(){
    @Override
    public void updateItem(Person item, boolean empty){
        super.updateItem(item, empty);

        if (item == null || empty) {
            setStyle("");
        } else {
            //Now 'item' has all the info of the Person in this row
            if (item.getName().equals("Edgar")) {
                //We apply now the changes in all the cells of the row
                for(int i=0; i<getChildren().size();i++){
                    ((Labeled) getChildren().get(i)).setTextFill(Color.RED);
                    ((Labeled) getChildren().get(i)).setStyle("-fx-background-color: yellow");
                }                        
            } else {
                if(getTableView().getSelectionModel().getSelectedItems().contains(item)){
                    for(int i=0; i<getChildren().size();i++){
                        ((Labeled) getChildren().get(i)).setTextFill(Color.WHITE);;
                    }
                }
                else{
                    for(int i=0; i<getChildren().size();i++){
                        ((Labeled) getChildren().get(i)).setTextFill(Color.BLACK);;
                    }
                }
            }
        }
    }
});

This is the best way I found to apply the change of style in all the cells of the row. If you use the method "getTableRow()" inside the Cell Factory, you can't modify their cell children.

NOTE 1: If you want to change the style of the text, you have to work in the cell. If you try to do this changes directly on the row, has no effect.

NOTE 2: If you are using a separated CSS file, don't write something like this:

.table-cell {
    -fx-text-fill: Black;
}

Because if you do this, all the Java code has no effect.

Takeo answered 9/9, 2016 at 15:51 Comment(2)
The logic of the code: the updateItem() method that we overwrite, it's called automatically whenever the cell has to be rendered. ... That is not true. It is only called, as the name suggests, when the underlying item changes, but not on resizes for example.Echt
I'm using this solution and it's working, partially... Until I scroll, the rows don't change its colour... Any suggestion?Catercousin
C
2

After many searches i found the answer. You need to set an id for specific row in table and set the color in external css file depending on row id. Here is the example where i change the color of error rows to red. Java code:

resultsTable.setRowFactory(row -> new TableRow<Result>() {
            @Override
            public void updateItem(Result item, boolean empty) {
                super.updateItem(item, empty);
                if (item == null) {
                    setStyle("");
                } else if (item.getResultType().equalsIgnoreCase("Error")) {
                    this.setId("error");
                } else {
                    this.setId("not-error");
                }
            }
        });

CSS file:

#error .text{
    -fx-fill : red;
}

#not-error .text{
    -fx-fill : black;
}
Cordle answered 8/11, 2019 at 15:0 Comment(2)
while possible, it's not the best approach: a) id should be unique across a scene (though not enforced) b) if you use it and set the one or other based on content,, you must reset it if null or empty. Styling as done in the other answers should work fine. An alternative is to use pseudoClasses (there are several QAs here, don't have any reference handy, though, sry)Intracranial
how to color the text in one column to mark the Tableview with colorCourthouse

© 2022 - 2024 — McMap. All rights reserved.