JavaFX:如何禁用TableView中的行? [英] JavaFX: How to disable a row in a TableView?

查看:603
本文介绍了JavaFX:如何禁用TableView中的行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在TableView中禁用一行。我有一个Tableview of Products,我已经知道需要禁用哪个产品(我从填充TableView的ObservableList获得了它的索引)。

I want to disable a row in a TableView. I have a Tableview of Products, and I already know which product needs to be disabled (I got the index of it from the ObservableList that fills the TableView).

如何在ObservableList中获取与Product关联的TableRow,其中我知道索引?

How do I get the TableRow that is associated with Product in the ObservableList, of which I know the index?

否则:是否有一种从TableView禁用特定TableRow的简单方法?

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

非常感谢任何帮助。

推荐答案

最好的方法是不使用索引,而是使用自定义行工厂并观察行中项目的相应属性。

The best way is not to use the index, but to use a custom row factory and observe the appropriate properties of the item in the row.

对于当前的API,这有点棘手,因为您可能需要观察表行的item属性的属性。您可以使用 Bindings。选择(...) 来执行此操作,但是当项目为空时(当前它将非常频繁),当前版本会发出许多多余的警告。我更喜欢使用 EasyBind框架来实现此类功能。

This is slightly tricky with the current API, as you probably need to observe a property of the item property of the table row. You can use Bindings.select(...) to do this, but the current version spews out lots of superfluous warnings when the item is null (which it will be quite frequently). I prefer to use the EasyBind framework for this kind of functionality.

此示例禁用所显示项目的value属性小于5的所有表行:

This example disables all table rows for which the value property 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's 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're really disabling based on the index, you can use a very similar technique:

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

然后调用 disabledRowIndex.set(...)将禁用所提供索引处的行。

Then calling disabledRowIndex.set(...) will disable the row at the supplied index.

请注意,禁用语义可能不完全是你的意思想。这会禁用表行的所有输入(例如,不会启用删除按钮);但是它不会阻止选择行(键盘导航由tableview本身管理,因此您仍然可以使用键盘选择行)。定义自定义选择行为更具挑战性。

Notice that the disable semantics might not be exactly what you want. This disables all input to the table row (so, for example, the delete button will not be enabled); however it doesn't prevent selection of the row (keyboard navigation is managed by the tableview itself, so you can still select the row using the keyboard). Defining custom selection behavior is more challenging.

这篇关于JavaFX:如何禁用TableView中的行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆