JavaFX: how to disable row in TableView?

I want to disable a row in a TableView. I have a Tableview of Products, and I already know which product to disable (I got its index from the ObservableList that populates the TableView).

How to get the TableRow associated with a product in an ObservableList that I know of an index about?

Otherwise: is there an easy way to disable a specific TableRow from a TableView?

Any help is greatly appreciated.

+5
source share
1 answer

The best way is not to use an index, but to use a custom factory string and observe the corresponding properties of the element in the string.

This is a bit complicated with the current API, since you probably need to observe the item property of the table row property. You can use Bindings.select(...) , but the current version displays a lot of unnecessary warnings when the element is null (which will be quite common). I prefer to use the EasyBind structure for this kind of function.

In this example, all rows of the table are disabled for which the property value of the displayed item is less than 5:

 import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; import java.util.function.Function; import javafx.application.Application; import javafx.beans.binding.Bindings; import javafx.beans.property.IntegerProperty; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.beans.value.ObservableValue; import javafx.collections.ObservableList; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.ContentDisplay; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableRow; import javafx.scene.control.TableView; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import org.fxmisc.easybind.EasyBind; public class DisabledTableRowExample extends Application { @Override public void start(Stage primaryStage) { TableView<Item> table = new TableView<>(); table.getItems().addAll(createData()); TableColumn<Item, Item> deleteCol = createTableColumn("Delete", ReadOnlyObjectWrapper<Item>::new); deleteCol.setCellFactory(this::createDeleteCell); table.getColumns().addAll(Arrays.asList( createTableColumn("Name", Item::nameProperty), createTableColumn("Value", Item::valueProperty), deleteCol )); // A row factory that returns a row that disables itself whenever the // item it displays has a value less than 5: table.setRowFactory(tv -> { TableRow<Item> row = new TableRow<>(); // use EasyBind to access the valueProperty of the itemProperty of the cell: row.disableProperty().bind( EasyBind.select(row.itemProperty()) // start at itemProperty of row .selectObject(Item::valueProperty) // map to valueProperty of item, if item non-null .map(x -> x.intValue() < 5) // map to BooleanBinding via intValue of value < 5 .orElse(false)); // value to use if item was null // it also possible to do this with the standard API, but there are lots of // superfluous warnings sent to standard out: // row.disableProperty().bind( // Bindings.selectInteger(row.itemProperty(), "value") // .lessThan(5)); return row ; }); BorderPane root = new BorderPane(table); Scene scene = new Scene(root, 600, 400); primaryStage.setScene(scene); primaryStage.show(); } private List<Item> createData() { Random rng = new Random(); List<Item> data = new ArrayList<>(); for (int i=1; i<=20; i++) { data.add(new Item("Item "+i, rng.nextInt(10))); } return data ; } private <S,T> TableColumn<S, T> createTableColumn(String name, Function<S, ObservableValue<T>> propertyMapper) { TableColumn<S,T> col = new TableColumn<>(name); col.setCellValueFactory(cellData -> propertyMapper.apply(cellData.getValue())); return col ; } private TableCell<Item, Item> createDeleteCell(TableColumn<Item, Item> col) { ObservableList<Item> itemList = col.getTableView().getItems(); TableCell<Item, Item> cell = new TableCell<>(); cell.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); Button button = new Button("Delete"); button.setOnAction(event -> itemList.remove(cell.getItem())); cell.graphicProperty().bind(Bindings.when(cell.emptyProperty()).then((Node)null).otherwise(button)); return cell ; } public static class Item { private final StringProperty name = new SimpleStringProperty(this, "name"); private final IntegerProperty value = new SimpleIntegerProperty(this, "value"); public final StringProperty nameProperty() { return this.name; } public final java.lang.String getName() { return this.nameProperty().get(); } public final void setName(final java.lang.String name) { this.nameProperty().set(name); } public final IntegerProperty valueProperty() { return this.value; } public final int getValue() { return this.valueProperty().get(); } public final void setValue(final int value) { this.valueProperty().set(value); } public Item(String name, int value) { setName(name); setValue(value); } } public static void main(String[] args) { launch(args); } } 

If you really disconnect based on the index, you can use a very similar method:

 IntegerProperty disabledRowIndex = new SimpleIntegerProperty(); // ... // in row factory do: row.disableProperty().bind(row.indexProperty.isEqualTo(disabledRowIndex)); 

Then calling disabledRowIndex.set(...) will disconnect the row in the specified pointer.

Note that disable semantics may not be exactly what you want. This disables all input in the table row (for example, the delete button will not be enabled); however, it does not prevent the selection of a row (keyboard navigation is controlled by the table itself, so you can select a row using the keyboard). Defining custom selection behavior is more complex.

+8
source

Source: https://habr.com/ru/post/1013083/


All Articles