0
votes

I have made my own selection column, and in the column header I have a checkbox that when I click on changes the value of the cell I have set for the cellValueFactory which triggers the method updateItem in the TableCell which fires a custom event that I need to work with.

public abstract class GeneratedPersistableBeanFX extends GeneratedPersistableBean {

private static CheckBox select_all;

public GeneratedPersistableBeanFX(int beanState) {
    super(beanState);
    // TODO Auto-generated constructor stub
}
private BooleanProperty SelectedInGridProperty = new SimpleBooleanProperty(false);

public BooleanProperty selectedInGridProperty() {
    return SelectedInGridProperty;
}

public Boolean getSelectedInGrid() {
    return SelectedInGridProperty.getValue();
}

public void setSelectedInGrid(Boolean val) {
    SelectedInGridProperty.setValue(val);
}

public static CustomTableColumn<GeneratedPersistableBeanFX, Boolean> getTableColumnSelectedInGrid(String columnName) {
    getSelectAllCheckBox();

    String columnHeader = ((columnName == null) ? "Selected" : columnName);
    CustomTableColumn<GeneratedPersistableBeanFX, Boolean> theCol = new CustomTableColumn<>(columnHeader);
    theCol.setId(columnHeader);
    theCol.setMinWidth(32);
    theCol.setColumnName(columnHeader);
    theCol.setGraphic(getSelectAllCheckBox());
    theCol.setStyle("-fx-alignment: CENTER;");
    theCol.setCellValueFactory(cellData -> cellData.getValue().selectedInGridProperty());
    theCol.setCellFactory(new Callback<TableColumn<GeneratedPersistableBeanFX, Boolean>, TableCell<GeneratedPersistableBeanFX, Boolean>>() {
        @Override
        public TableCell<GeneratedPersistableBeanFX, Boolean> call(TableColumn<GeneratedPersistableBeanFX, Boolean> col) {

            final TableCell<GeneratedPersistableBeanFX, Boolean> cell = new TableCell<GeneratedPersistableBeanFX, Boolean>() {

                @Override
                public void updateItem(Boolean item, boolean empty) {
                    super.updateItem(item, empty);
                    setText(null);
                    // setMinHeight(40);
                    if (item == null) {
                        setGraphic(null);
                    }
                    else {
                        if (item.booleanValue() && getGraphic() == null) {
                            setGraphic(CustomImageLoaderFX.getInstance().getImageView("check.png", 16));
                        }
                        else if (item.booleanValue() && getGraphic() != null) {
                            getGraphic().setVisible(true);
                        }
                        else if (getGraphic() != null) {
                            getGraphic().setVisible(false);
                        }
                        if (getTableView() != null && getTableRow() != null && item != null) {
                            getTableView().fireEvent(
                                    new CustomTableColumnSelectionChangedEvent((GeneratedPersistableBeanFX) getTableRow().getItem(), item.booleanValue()));
                        }
                    }
                }
            };

            cell.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent event) {
                    ObservableValue<Boolean> ov = ((TableCell<GeneratedPersistableBeanFX, Boolean>) event.getSource()).getTableColumn()
                            .getCellObservableValue(((TableCell<GeneratedPersistableBeanFX, Boolean>) event.getSource()).getIndex());
                    SimpleBooleanProperty sp = (SimpleBooleanProperty) ov;
                    if (sp == null) {
                        return;
                    }
                    GeneratedPersistableBeanFX bean = (GeneratedPersistableBeanFX) ((TableCell<GeneratedPersistableBeanFX, Boolean>) event.getSource())
                            .getTableRow().getItem();
                    if (sp.getValue() == false) {
                        sp.setValue(true);
                    }
                    else {
                        sp.setValue(false);
                    }
                }
            });
            return cell;
        }

    });
    return theCol;
}

public static CheckBox getSelectAllCheckBox() {
    if (select_all == null) {
        select_all = new CheckBox();
        select_all.setOnAction(e -> selectAllBoxes(e));
    }
    return select_all;
}

private static void selectAllBoxes(ActionEvent e) {
    CustomTableView<GeneratedPersistableBeanFX> table = getTableViewFromCheckBox(((CheckBox) e.getSource()).getParent());
    ObservableList<GeneratedPersistableBeanFX> items = table.getItems();
    for (GeneratedPersistableBeanFX item : items) {
        item.setSelectedInGrid(((CheckBox) e.getSource()).isSelected());
        //What I tried to force to trigger updateItem on all rows
        table.getColumns().get(0).setVisible(false);
        table.getColumns().get(0).setVisible(true);
    }
}

@SuppressWarnings("unchecked")
private static CustomTableView<GeneratedPersistableBeanFX> getTableViewFromCheckBox(Parent parent) {
    if (parent instanceof CustomTableView<?>) {
        return (CustomTableView<GeneratedPersistableBeanFX>) parent;
    }
    else if (parent != null && parent.getParent() != null) {
        return getTableViewFromCheckBox(parent.getParent());
    }
    else {
        return null;
    }
}   

For example I have a JME 3D window imbedded in a Dialog that shows the 3D Models of materials and there is also a tableview with all the materials. When I click on select all only the materials visible in the tableview viewport are being highlighted in my 3D and as I scroll down it has the funny behaviour that the remaining materials get highlighted as I scroll down.

Problem is, the method updateItem is only called for cells currently visible in the TableViews viewport.

Is there any way to circumvent this behaviour and make it call for every single cell of every item in the list regardless of visibility?

1
Post your GeneratedPersistableBeanFX class (at least the parts relevant to the selectedInGridProperty). - James_D
Done, altough I really think its down to javafx behaviour rather than code. Noticed this behaviour too in other tableviews where we would color some materials in a table with css.And the last row would not get colored if it was say only 1/2 visible. Had to adjust the size of the tableview so that the rows fit perfectly. Altough that may be a down to css, here its strictly value related. - 404KnowledgeNotFound

1 Answers

0
votes

So I read up a bit on the issue, and found out that the problem I had was because a TableView amongst others, uses virtualized cells,which are explained better here.

Basically one should never use the updateItem method to do anything logic related, its only recommended for changing the visuals of the cell.

With that in mind I simply moved the moment when I fired my event from the updateItem method to the user events clicking on the select all checkbox or clicking on the cell itself. Its not as neat but it works.

 private static void selectAllBoxes(ActionEvent e) {
    CustomTableView<GeneratedPersistableBeanFX> table = getTableViewFromCheckBox(((CheckBox) e.getSource()).getParent());
    if (table == null) {
        return;
    }
    ObservableList<GeneratedPersistableBeanFX> items = table.getItems();
    for (GeneratedPersistableBeanFX item : items) {
        item.setSelectedInGrid(((CheckBox) e.getSource()).isSelected());
        table.fireEvent(new CustomTableColumnSelectionChangedEvent(item, ((CheckBox) e.getSource()).isSelected()));
    }
}
 cell.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
    @SuppressWarnings("unchecked")
    @Override
    public void handle(MouseEvent event) {
        SimpleBooleanProperty sp = (SimpleBooleanProperty) (((TableCell<GeneratedPersistableBeanFX, Boolean>) event.getSource())
            .getTableColumn().getCellObservableValue(((TableCell<GeneratedPersistableBeanFX, Boolean>) event.getSource()).getIndex()));
        if (sp == null) {
            return;
        }
        if (sp.getValue() == false) {
            sp.setValue(true);
        }
        else {
            sp.setValue(false);
        }
        ((TableCell<GeneratedPersistableBeanFX, Boolean>) event.getSource()).getTableView().fireEvent(
            new CustomTableColumnSelectionChangedEvent((GeneratedPersistableBeanFX) ((TableCell<GeneratedPersistableBeanFX, Boolean>) event
            .getSource()).getTableRow().getItem(), sp.getValue().booleanValue()));

    }
});

A weekend away from coding and work can sometimes do wonders! I just didnt realize this at all on Fr.