Reputation: 538
I have this simple code:
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
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.VBox;
import javafx.stage.Stage;
public class Example extends Application
{
@Override
public void start(Stage stage) throws Exception
{
TableView<Integer> table = new TableView<>();
TableColumn<Integer, Integer> column = new TableColumn<>();
column.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue()));
ObservableList<Integer> items = FXCollections.observableArrayList();
table.getColumns().add(column);
table.setItems(items);
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
for (int i = 0; i < 500; i++)
items.add((int) (Math.random() * 500));
BooleanProperty disable = new SimpleBooleanProperty();
table.setRowFactory(param ->
{
TableRow<Integer> row = new TableRow<>();
row.disableProperty().bind(disable);
row.disableProperty().addListener((observable, oldValue, newValue) ->
{
if (newValue)
row.setStyle("-fx-background-color: red");
else
row.setStyle("");
});
return row;
});
Button button = new Button("Disable all rows");
button.setOnAction(event -> disable.set(true));
stage.setScene(new Scene(new VBox(table, button)));
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
When I run it and press the button, it should color all the rows. It works, until you scroll the table down. Then something strange starts happening, some rows won't be colorful and when you scroll back, they'll be colorful and some others won't be.
But when you scroll first and then press the button, it'll work fine. I have no idea what is happening there, it seems like a bug to me.
In the original code, I need to disable some rows because I need to disable a table check-box. Nevertheless, it won't work even if we switch the disable property to the editable property.
Does anyone have an idea how to fix this and why it doesn't work?
Upvotes: 0
Views: 831
Reputation: 209225
When you scroll, the table may need to create a few more rows. If rows are created after the button is pressed, you first bind the disable
property of the new row to the boolean property you create (so the row's disable property is set to true), then you register a listener with the row's disable property that changes the style. Since the row's disable property never changes after the listener is registered, it is never invoked, and the style never changes.
You can do
table.setRowFactory(param ->
{
TableRow<Integer> row = new TableRow<>();
row.disableProperty().addListener((observable, oldValue, newValue) ->
{
if (newValue)
row.setStyle("-fx-background-color: red");
else
row.setStyle("");
});
row.disableProperty().bind(disable);
return row;
});
or you can just use a binding directly:
table.setRowFactory(param ->
{
TableRow<Integer> row = new TableRow<>();
row.styleProperty().bind(Bindings
.when(disable)
.then("-fx-background-color: red;")
.otherwise(""));
row.disableProperty().bind(disable);
return row;
});
or you can use an external style sheet with
.table-row-cell:disabled {
-fx-background-color:red ;
}
and omit the listener/binding for the style entirely:
table.setRowFactory(param ->
{
TableRow<Integer> row = new TableRow<>();
row.disableProperty().bind(disable);
return row;
});
Upvotes: 1