Reputation: 634
I want to create a TableView
with Buttons
in each row to delete the specific row. Therefore I created a class extending TableCell
with a Button in it. So I set the CellFactory
of the column like this:
clmRemoveButtons.setCellFactory(c -> new RemovingCell(clients));
Everything works fine. I'm able to delete the rows and the buttons are displayed correctly, but there is one problem. There are buttons in the whole column. It doesn't matter how many items are in the ObservableList
of data. The buttons in rows with items work correctly, but when I click on a button out of this range I get a IndexOutOfBoundsException
(that's correct, because there is no data to remove at this point).
So my question is, what do I do wrong and how can I avoid this issue?
best regards
EDIT: Code of RemovingCell
(Note: HoverButton
is a control extending JavaFX Button
with some settings (size etc.), so nothing special.
public class RemovingCell extends TableCell<Client, Client> {
private HoverButton hb = new HoverButton(Color.RED);
public RemovingCell(ObservableList<Client> data) {
super();
setAlignment(Pos.CENTER);
try {
ImageView imgv = new ImageView(new Image(new FileInputStream(
"img/Remove.png")));
imgv.setFitWidth(15);
imgv.setPreserveRatio(true);
imgv.setSmooth(true);
hb.setGraphic(imgv);
hb.setTooltip(ControlFactory.getTooltip("Klient entfernen"));
hb.setOnAction(event -> {
data.remove(getTableRow().getIndex());
});
setGraphic(hb);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
Upvotes: 0
Views: 475
Reputation: 209225
TableView
s that are larger than needed to contain all the data in the table fill the extra space with empty cells. Your TableCell
needs to check whether or not the cell is empty before deciding whether or not to include a button in there. You can do this with a listener on the cell's emptyProperty()
, or a binding to it:
public class RemovingCell extends TableCell<Client, Client> {
private HoverButton hb = new HoverButton(Color.RED);
public RemovingCell(ObservableList<Client> data) {
super();
setAlignment(Pos.CENTER);
try {
ImageView imgv = new ImageView(new Image(new FileInputStream(
"img/Remove.png")));
imgv.setFitWidth(15);
imgv.setPreserveRatio(true);
imgv.setSmooth(true);
hb.setGraphic(imgv);
hb.setTooltip(ControlFactory.getTooltip("Klient entfernen"));
hb.setOnAction(event -> {
data.remove(getTableRow().getIndex());
});
// conditionally set the graphic:
// setGraphic(hb);
emptyProperty().addListener( (obs, wasEmpty, isNowEmpty) -> {
if (isNowEmpty) {
setGraphic(null);
} else {
setGraphic(hb);
}
});
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
With a binding you can do
graphicProperty().bind(Bindings.when(emptyProperty())
.then((Node)null)
.otherwise(hb));
instead of adding the listener to the emptyProperty()
. The choice between the two is just a matter of style.
Upvotes: 2