A relative Java newbie question.
I'm trying set a TableRow
's background colour based on whether or not it's selected and/or whether or not a boolean value in the data model is true.
I've found ways of doing each but not both together in the same setRowFactory
.
What I would like to end up with is this (albeit with horrible colours for example purposes only!):
How would I go about achieving that?
This is what I found wrt changing row colour based on selection. It's adapted from user James_D's answer here https://community.oracle.com/thread/3528543.
final ObservableSet<Integer> selectedRowIndexes = FXCollections.observableSet();
table.getSelectionModel().getSelectedCells().addListener((Change<? extends TablePosition> change) -> {
selectedRowIndexes.clear();
selectedRowIndexes.add( (table.getSelectionModel().getSelectedCells().get(0)).getRow() );
});
table.setRowFactory(tv -> {
TableRow<TestModel> row = new TableRow<>();
BooleanBinding selected = Bindings.createBooleanBinding(() ->
selectedRowIndexes.contains(new Integer(row.getIndex())), row.indexProperty(), selectedRowIndexes);
row.styleProperty().bind(Bindings.when(selected)
.then("-fx-background-color: green;")
.otherwise(""));
return row;
});
And this is what I found wrt changing row colour based on a cell value. It's adapted from user kleopatra's answer here TreeTableView : setting a row not editable.
table.setRowFactory(tv -> {
TableRow<TestModel> row = new TableRow<TestModel>() {
@Override
public void updateItem(TestModel testmodel, boolean empty) {
super.updateItem(testmodel, empty);
boolean locked = false;
if ( getItem() != null ) {
locked = getItem().lockedProperty().get();
setEditable( ! locked);
}
if (!isEmpty() && locked ) {
setStyle("-fx-background-color: red;");
}else{
setStyle(null);
}
}
};
return row;
});
However, I've ended up with two row factories and haven't been able to figure out how merge them into one.
If it helps, here is the MVCE I've been playing with. It has the two row factories. I haven't included my (many!) attempts to merge them as none worked.
I'm using JavaFX8 (JDK1.8.0_181), NetBeans 8.2 and Scene Builder 8.3.
package test31;
import java.util.Arrays;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.collections.ObservableSet;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.converter.BooleanStringConverter;
public class Test31 extends Application {
private Parent createContent() {
TableView<TestModel> table = new TableView<>();
ObservableList<TestModel> olTestModel = FXCollections.observableArrayList(testmodel -> new Observable[] {});
olTestModel.add(new TestModel("1", true));
olTestModel.add(new TestModel("2", false));
olTestModel.add(new TestModel("3", false));
olTestModel.add(new TestModel("4", true));
olTestModel.add(new TestModel("5", false));
TableColumn<TestModel, String> colText = new TableColumn<>("textfield");
colText.setCellValueFactory(cb -> cb.getValue().textFieldProperty());
colText.setCellFactory(TextFieldTableCell.forTableColumn());
TableColumn<TestModel, Boolean> colBoolean = new TableColumn<>("locked");
colBoolean.setCellValueFactory(cb -> cb.getValue().lockedProperty());
colBoolean.setCellFactory(TextFieldTableCell.forTableColumn(new BooleanStringConverter()));
table.getSelectionModel().setCellSelectionEnabled(true);
table.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
table.setEditable(true);
table.getColumns().addAll(Arrays.asList(colText, colBoolean));
table.setItems(olTestModel);
//****************************************************************************************
//First row factory: Set background colour based on whether or not the row is selected
final ObservableSet<Integer> selectedRowIndexes = FXCollections.observableSet();
table.getSelectionModel().getSelectedCells().addListener((Change<? extends TablePosition> change) -> {
selectedRowIndexes.clear();
selectedRowIndexes.add( (table.getSelectionModel().getSelectedCells().get(0)).getRow() );
});
table.setRowFactory(tv -> {
TableRow<TestModel> row = new TableRow<>();
BooleanBinding selected = Bindings.createBooleanBinding(() ->
selectedRowIndexes.contains(new Integer(row.getIndex())), row.indexProperty(), selectedRowIndexes);
row.styleProperty().bind(Bindings.when(selected)
.then("-fx-background-color: green;")
.otherwise(""));
return row;
});
//****************************************************************************************
//Second row factory: Set background colour based on the value of a boolean property
table.setRowFactory(tv -> {
TableRow<TestModel> row = new TableRow<TestModel>() {
@Override
public void updateItem(TestModel testmodel, boolean empty) {
super.updateItem(testmodel, empty);
boolean locked = false;
if ( getItem() != null ) {
locked = getItem().lockedProperty().get();
setEditable( ! locked);
}
if (!isEmpty() && locked ) {
setStyle("-fx-background-color: red;");
}else{
setStyle(null);
}
}
};
return row;
});
BorderPane content = new BorderPane(table);
return content;
}
public class TestModel {
private StringProperty textField;
private BooleanProperty locked;
public TestModel() {
this("", false);
}
public TestModel(
String textField,
boolean locked
) {
this.textField = new SimpleStringProperty(textField);
this.locked = new SimpleBooleanProperty(locked);
}
public String getTextField() {
return textField.get().trim();
}
public void setTextField(String textField) {
this.textField.set(textField);
}
public StringProperty textFieldProperty() {
return textField;
}
public boolean getLocked() {
return locked.get();
}
public void setLocked(boolean locked) {
this.locked.set(locked);
}
public BooleanProperty lockedProperty() {
return locked;
}
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setTitle("Test");
stage.setWidth(500);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}