0

I have the following piece of code to set background Color of a TableRow,

column.setCellFactory((TableColumn<Model, Integer> p) -> {
           ComboBoxTableCell cell = new ComboBoxTableCell(FXCollections.observableArrayList(0, 1)) {
               @Override
               public void updateItem(Object item, boolean empty) {
                   super.updateItem(item, empty);
                   if (!empty && item != null) {
                       if(Integer.valueOf(item.toString()) == 1){
                           getTableRow().setStyle("-fx-background-color: khaki;");
                       }else if(Integer.valueOf(item.toString()) == 0){
                           getTableRow().setStyle(null);
                       }
                   }
               }
           };
           return cell;
        });

The problem is when i select the row with background set to some color, the default blue color which indicates selection goes behind. (like below)

enter image description here

How can i retain the default selection color?

user3164187
  • 1,278
  • 2
  • 17
  • 42

1 Answers1

2

Inline style has higher priority than CSS stylesheets. Therefore the background for selected rows is also overridden. The way the background is constructed requires you to use specify -fx-control-inner-background-alt and -fx-control-inner-background instead.

[...].setStyle("-fx-control-inner-background: khaki; -fx-control-inner-background-alt: khaki;")

However there's an issue that's much worse:

You set the style from the TableCells. Since TableView is responsible for assigning the items to the cells, the order this is done is an implementation detail resulting in arbitrary outcomes, if you use the cell type in different columns. Even if you use these cells in only one column, you never handle the case where the cells become empty, so even empty cells may still contain the new color.

Row styling belongs to the table rows.

Also you get the most flexibility, if you use a PseudoClass and a CSS stylesheet.

E.g.

final PseudoClass one = PseudoClass.getPseudoClass("one");
tableView.setRowFactory(t -> new TableRow<Model>() {

    private ChangeListener<Integer> listener = (o, oldValue, newValue) -> {
        pseudoClassStateChanged(one, newValue == 1);
    };

    @Override
    protected void updateItem(Model model, boolean empty) {
        if (getItem() != null) {
            getItem().myValueProperty().removeListener(listener);
        }

        super(model, empty);

        if (empty || model == null) {
            listener.changed(null, 0, -1);
        } else {
            model.myValueProperty().addListener(listener);
            listener.changed(null, 0, model.getMyValue());
        }
    }


});

CSS stylesheet

.table-row-cell:one {
    -fx-control-inner-background: khaki;
    -fx-control-inner-background-alt: khaki;
}

Furthermore you should use type parameters to avoid converting to your item from Integer to String and back to Integer (which should be replaced by a cast, if it needs to be done this way. In this case it's better not to use raw types.).

final ObservableList<Integer> values = FXCollections.observableArrayList(0, 1);

column.setCellFactory((TableColumn<Model, Integer> p) -> {
    ComboBoxTableCell<Model, Integer> cell = new ComboBoxTableCell<Model, Integer>(values) {
        @Override
        protected void updateItem(Integer item, boolean empty) {
            ...
        }
    };
    return cell;
});
fabian
  • 67,623
  • 12
  • 74
  • 102