0

I'm using TabelView with 2 columns:

@FXML
private TableView<Person> personTable;
@FXML
private TableColumn<Person, String> firstNameColumn;
@FXML
private TableColumn<Person, String> lastNameColumn;


public class Person {

    private final StringProperty firstName;
    private final StringProperty lastName;


    /**
     * Default constructor.
     */
    public Person() {
        this(null, null);
    }

    /**
     * Constructor with some initial data.
     * 
     * @param firstName
     * @param lastName
     */
    public Person(String firstName, String lastName) {
        this.firstName = new SimpleStringProperty(firstName);
        this.lastName = new SimpleStringProperty(lastName);        
    }

    public String getFirstName() {
        return firstName.get();
    }

    public void setFirstName(String firstName) {
        this.firstName.set(firstName);
    }

    public StringProperty firstNameProperty() {
        return firstName;
    }

    public String getLastName() {
        return lastName.get();
    }

    public void setLastName(String lastName) {
        this.lastName.set(lastName);
    }

    public StringProperty lastNameProperty() {
        return lastName;
    }


}

I have a logic which calculate row number, and I need to set the background of this row to red (every several seconds I'm calculating the row and I need to set the caculcated row background to red.

I check those Q's:

Colouring table row in JavaFX

But it does help. So I can I set a random row, it's background color ?

James_D
  • 201,275
  • 16
  • 291
  • 322
user3668129
  • 4,318
  • 6
  • 45
  • 87

1 Answers1

2

Depending on exactly what you need, you can do:

ObjectProperty<Person> criticalPerson = new SimpleObjectProperty<>();

personTable.setRowFactory(tv -> {
    TableRow<Person> row = new TableRow<>();
    BooleanBinding critical = row.itemProperty().isEqualTo(criticalPerson);
    row.styleProperty().bind(Bindings.when(critical)
        .then("-fx-background-color: red ;")
        .otherwise(""));
    return row ;
});

Here is a SSCCE:

import java.util.function.Function;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class HighlightTableRows extends Application {

    @Override
    public void start(Stage primaryStage) {


        TableView<Person> table = new TableView<>();
        table.getColumns().add(column("First Name", Person::firstNameProperty));
        table.getColumns().add(column("Last Name", Person::lastNameProperty));

        for (int i = 1 ; i <=50 ; i++) {
            table.getItems().add(new Person("Person"+i, "McPerson"+i));
        }

        ObjectProperty<Person> criticalPerson = new SimpleObjectProperty<>();


        table.setRowFactory(tv -> {
            TableRow<Person> row = new TableRow<>();
            BooleanBinding critical = row.itemProperty().isEqualTo(criticalPerson).and(row.itemProperty().isNotNull());
            row.styleProperty().bind(Bindings.when(critical)
                .then("-fx-background-color: red ;")
                .otherwise(""));
            return row ;
        });

        BorderPane root = new BorderPane(table);

        Button apply = new Button("Make critical");
        apply.setOnAction(e -> criticalPerson.set(table.getSelectionModel().getSelectedItem()));
        apply.disableProperty().bind(table.getSelectionModel().selectedItemProperty().isNull());
        Button clear = new Button("Clear");
        clear.setOnAction(e -> criticalPerson.set(null));

        HBox controls = new HBox(5, apply, clear);
        controls.setAlignment(Pos.CENTER);
        controls.setPadding(new Insets(5));
        root.setBottom(controls);

        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private <S,T> TableColumn<S,T> column(String text, Function<S, ObservableValue<T>> prop) {
        TableColumn<S,T> col = new TableColumn<>(text);
        col.setCellValueFactory(cellData -> prop.apply(cellData.getValue()));
        return col ;
    }

    public class Person {

        private final StringProperty firstName;
        private final StringProperty lastName;

        /**
         * Default constructor.
         */
        public Person() {
            this(null, null);
        }

        /**
         * Constructor with some initial data.
         * 
         * @param firstName
         * @param lastName
         */
        public Person(String firstName, String lastName) {
            this.firstName = new SimpleStringProperty(firstName);
            this.lastName = new SimpleStringProperty(lastName);
        }

        public String getFirstName() {
            return firstName.get();
        }

        public void setFirstName(String firstName) {
            this.firstName.set(firstName);
        }

        public StringProperty firstNameProperty() {
            return firstName;
        }

        public String getLastName() {
            return lastName.get();
        }

        public void setLastName(String lastName) {
            this.lastName.set(lastName);
        }

        public StringProperty lastNameProperty() {
            return lastName;
        }

    }

    public static void main(String[] args) {
        launch(args);
    }
}

If multiple rows might need to be red at the same time, make the obvious modifications with an ObservableList containing the items whose rows should be red, etc. You might also consider adding a BooleanProperty to the model class and letting the table row observe it.

James_D
  • 201,275
  • 16
  • 291
  • 322
  • 1
    I'm missing something. 1. it not compiled. 2. I cant see how I can transfer the calulcated row number to this ? – user3668129 Jun 28 '17 at 18:13
  • @user3668129 What's the compile error? For your second question, just do `criticalPerson.set(personTable.getItems().get(rowNumber));` (or `criticalPerson.set(person);` if it's easier to calculate the actual person instead of their index). – James_D Jun 28 '17 at 18:23
  • "when" is not recognized – user3668129 Jun 28 '17 at 18:25
  • Sounds like you have the wrong import for `Bindings`? – James_D Jun 28 '17 at 18:26
  • import javafx.beans.binding.BooleanBinding; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; – user3668129 Jun 28 '17 at 18:29
  • error: The method when(BooleanBinding) is undefined for the type Bindings – user3668129 Jun 28 '17 at 18:30
  • @user3668129 So what import do you have for `Bindings`? – James_D Jun 28 '17 at 18:30
  • can you Please display an example how to use your code when I need to set color multiple rows ? – user3668129 Jun 28 '17 at 18:46
  • @user3668129 Just use an `ObservableList`, and create a binding that checks if the list contains the row's `item`. – James_D Jun 28 '17 at 18:53
  • your solution will no refresh (from red to "") when need to clear the red colour (criticalPerson.set(null)) –  Jun 29 '17 at 12:49
  • @Boom It does for me. Added a complete example as so many people seem to be having trouble adapting this. – James_D Jun 29 '17 at 13:05