Java 设置TableView单个单元格的禁用属性

Java 设置TableView单个单元格的禁用属性,java,uitableview,javafx,tableview,tablecell,Java,Uitableview,Javafx,Tableview,Tablecell,如何在TableView中为单个单元格设置禁用属性 下面是我的场景:一列有一个ComboBoxTableCell,根据选择的项目,同一行上的某些单元格将被禁用 例如: 如果选择类型A,则输入A启用,输入B禁用,反之亦然 我所说的禁用是指清除、灰显和不可编辑 我的场景的一个简单示例: TableTest.java package minimalexample; import javafx.application.Application; import javafx.collections.FXC

如何在TableView中为单个单元格设置禁用属性

下面是我的场景:一列有一个
ComboBoxTableCell
,根据选择的项目,同一行上的某些单元格将被禁用

例如:

如果选择类型A,则输入A启用,输入B禁用,反之亦然

我所说的禁用是指清除、灰显和不可编辑

我的场景的一个简单示例:

TableTest.java

package minimalexample;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TableTest extends Application {

    private TableView itemsTable;

    ObservableList<ItemsTableLine> items;

    @Override
    public void start(Stage primaryStage) {

        items = FXCollections.observableArrayList();
        items.addAll(new ItemsTableLine("A","1","2"),
                     new ItemsTableLine("A","3","4"),
                     new ItemsTableLine("B","5", "6"),
                     new ItemsTableLine());

        ItemsTable itemsTableParent = new ItemsTable();
        itemsTable = itemsTableParent.makeTable(items);

        VBox root = new VBox();        
        root.getChildren().addAll(itemsTable);

        Scene scene = new Scene(root, 200, 100);
        primaryStage.setTitle("Minimal Example");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

package minimalexample;


import javafx.util.Callback;
import javafx.application.Platform;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Pos;

import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;

import javafx.collections.ObservableList;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.ComboBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

public class ItemsTable {

    private String lastKey = null;

    // This will be exposed through a getter to be updated from list in LoadsTable
    private TableColumn<ItemsTableLine, ItemType> typeCol;
    private TableColumn<ItemsTableLine, String> inputACol;
    private TableColumn<ItemsTableLine, String> inputBCol;

    public TableView makeTable(ObservableList<ItemsTableLine> items) {

        TableView tv = new TableView(items);
        tv.setEditable(true);

        Callback<TableColumn<ItemsTableLine, String>, TableCell<ItemsTableLine, String>> txtCellFactory
                = (TableColumn<ItemsTableLine, String> p) -> {
                    return new EditingCell();
                };

        ObservableList<ItemType> itemTypeList
                = FXCollections.observableArrayList(ItemType.values());
        typeCol = new TableColumn<>("Type");
        inputACol  = new TableColumn<>("Input A");
        inputBCol   = new TableColumn<>("Input B");

        typeCol.setCellValueFactory(new Callback<CellDataFeatures<ItemsTableLine, ItemType>, ObservableValue<ItemType>>() {

            @Override
            public ObservableValue<ItemType> call(CellDataFeatures<ItemsTableLine, ItemType> param) {
                ItemsTableLine lineItem = param.getValue();
                String itemTypeCode = lineItem.typeProperty().get();
                ItemType itemType = ItemType.getByCode(itemTypeCode);
                return new SimpleObjectProperty<>(itemType);
            }
        });

        inputACol.setCellValueFactory(new PropertyValueFactory<>("inputA"));
        inputBCol.setCellValueFactory(new PropertyValueFactory<>("inputB"));
        typeCol.setCellFactory(ComboBoxTableCell.forTableColumn(itemTypeList));
        inputACol.setCellFactory(txtCellFactory);
        inputBCol.setCellFactory(txtCellFactory);
        typeCol.setOnEditCommit((CellEditEvent<ItemsTableLine, ItemType> event) -> {
            TablePosition<ItemsTableLine, ItemType> pos = event.getTablePosition();
            ItemType newItemType = event.getNewValue();
            int row = pos.getRow();
            ItemsTableLine lineItem = event.getTableView().getItems().get(row);
            lineItem.setType(newItemType.getCode());
        });
        inputACol.setOnEditCommit((TableColumn.CellEditEvent<ItemsTableLine, String> evt) -> {
            evt.getTableView().getItems().get(evt.getTablePosition().getRow())
                    .inputAProperty().setValue(evt.getNewValue().replace(",", "."));
        });
        inputBCol.setOnEditCommit((TableColumn.CellEditEvent<ItemsTableLine, String> evt) -> {
            evt.getTableView().getItems().get(evt.getTablePosition().getRow())
                    .inputBProperty().setValue(evt.getNewValue().replace(",", "."));
        });


        tv.getColumns().setAll(typeCol, inputACol, inputBCol);

        return tv;
    }

    private class EditingCell extends TableCell {
        private TextField textField;
        @Override public void startEdit() {
            if (!isEmpty()) {
                super.startEdit();
                createTextField();
                setText(null);
                setGraphic(textField);
                //setContentDisplay(ContentDisplay.GRAPHIC_ONLY); 
                Platform.runLater(() -> {//without this space erases text, f2 doesn't
                    textField.requestFocus();//also selects
                });
                if (lastKey != null) {
                    textField.setText(lastKey);
                    Platform.runLater(() -> {textField.deselect(); textField.end();});}
            }
        }
        public void commit() { commitEdit(textField.getText()); }

        @Override
        public void cancelEdit() {
            super.cancelEdit();
            try {
                setText(getItem().toString());
            } catch (Exception e) {
            }
            setGraphic(null);
        }

        @Override
        public void updateItem(Object item, boolean empty) {
            super.updateItem(item, empty);

            if (empty) {
                setText(null);
                setGraphic(null);
            } else if (isEditing()) {
                if (textField != null) {
                    textField.setText(getString());
                }
                setText(null);
                setGraphic(textField);
            } else {
                setText(getString());
                setGraphic(null);
                if (!getTableColumn().getText().equals("Name")) {
                    setAlignment(Pos.CENTER);
                }
            }
        }
        private void createTextField() {
            textField = new TextField(getString());
            textField.focusedProperty().addListener(
                    (ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) -> {
                        if (!arg2) { commitEdit(textField.getText()); }});
            textField.setOnKeyReleased((KeyEvent t) -> {
                if (t.getCode() == KeyCode.ENTER) {
                    commitEdit(textField.getText());
                    EditingCell.this.getTableView().getSelectionModel().selectBelowCell(); }
                if (t.getCode() == KeyCode.ESCAPE) { cancelEdit(); }});
            textField.addEventFilter(KeyEvent.KEY_RELEASED, (KeyEvent t) -> { 
                if (t.getCode() == KeyCode.DELETE) { t.consume();}});
        }
        private String getString() {return getItem() == null ? "" : getItem().toString();}
    }
}

package minimalexample;
import java.io.Serializable;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class ItemsTableLine implements Serializable {

    private StringProperty type;
    private StringProperty inputA;
    private StringProperty inputB;

    public StringProperty typeProperty() {return type;}
    public StringProperty inputAProperty()  {return inputA;  }
    public StringProperty inputBProperty()   {return inputB;}

    public ItemsTableLine() {
        super();
        type = new SimpleStringProperty("");
        inputA  = new SimpleStringProperty("");
        inputB   = new SimpleStringProperty("");
    }

    public ItemsTableLine(String...values) {
        this();
        type.set(values[0]);
        inputA.set(values[1]);
        inputB.set(values[2]);
    }

    // Setters required due to combobox 
    public void setType(String value) {
        type.set(value);
    }
}
package minimalexample;

public enum ItemType {
    TYPEA("A", "Type A"),
    TYPEB("B", "Type B");
    private String code;
    private String text;
    private ItemType(String code, String text) { this.code = code; this.text = text;}
    public String getCode() { return code; }
    public String getText() { return text; }
    public static ItemType getByCode(String genderCode) {
       for (ItemType g : ItemType.values()) if (g.code.equals(genderCode)) return g;
       return null;
    }
    @Override public String toString() { return this.text; }
}
ItemsType.java

package minimalexample;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TableTest extends Application {

    private TableView itemsTable;

    ObservableList<ItemsTableLine> items;

    @Override
    public void start(Stage primaryStage) {

        items = FXCollections.observableArrayList();
        items.addAll(new ItemsTableLine("A","1","2"),
                     new ItemsTableLine("A","3","4"),
                     new ItemsTableLine("B","5", "6"),
                     new ItemsTableLine());

        ItemsTable itemsTableParent = new ItemsTable();
        itemsTable = itemsTableParent.makeTable(items);

        VBox root = new VBox();        
        root.getChildren().addAll(itemsTable);

        Scene scene = new Scene(root, 200, 100);
        primaryStage.setTitle("Minimal Example");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

package minimalexample;


import javafx.util.Callback;
import javafx.application.Platform;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Pos;

import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;

import javafx.collections.ObservableList;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.ComboBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

public class ItemsTable {

    private String lastKey = null;

    // This will be exposed through a getter to be updated from list in LoadsTable
    private TableColumn<ItemsTableLine, ItemType> typeCol;
    private TableColumn<ItemsTableLine, String> inputACol;
    private TableColumn<ItemsTableLine, String> inputBCol;

    public TableView makeTable(ObservableList<ItemsTableLine> items) {

        TableView tv = new TableView(items);
        tv.setEditable(true);

        Callback<TableColumn<ItemsTableLine, String>, TableCell<ItemsTableLine, String>> txtCellFactory
                = (TableColumn<ItemsTableLine, String> p) -> {
                    return new EditingCell();
                };

        ObservableList<ItemType> itemTypeList
                = FXCollections.observableArrayList(ItemType.values());
        typeCol = new TableColumn<>("Type");
        inputACol  = new TableColumn<>("Input A");
        inputBCol   = new TableColumn<>("Input B");

        typeCol.setCellValueFactory(new Callback<CellDataFeatures<ItemsTableLine, ItemType>, ObservableValue<ItemType>>() {

            @Override
            public ObservableValue<ItemType> call(CellDataFeatures<ItemsTableLine, ItemType> param) {
                ItemsTableLine lineItem = param.getValue();
                String itemTypeCode = lineItem.typeProperty().get();
                ItemType itemType = ItemType.getByCode(itemTypeCode);
                return new SimpleObjectProperty<>(itemType);
            }
        });

        inputACol.setCellValueFactory(new PropertyValueFactory<>("inputA"));
        inputBCol.setCellValueFactory(new PropertyValueFactory<>("inputB"));
        typeCol.setCellFactory(ComboBoxTableCell.forTableColumn(itemTypeList));
        inputACol.setCellFactory(txtCellFactory);
        inputBCol.setCellFactory(txtCellFactory);
        typeCol.setOnEditCommit((CellEditEvent<ItemsTableLine, ItemType> event) -> {
            TablePosition<ItemsTableLine, ItemType> pos = event.getTablePosition();
            ItemType newItemType = event.getNewValue();
            int row = pos.getRow();
            ItemsTableLine lineItem = event.getTableView().getItems().get(row);
            lineItem.setType(newItemType.getCode());
        });
        inputACol.setOnEditCommit((TableColumn.CellEditEvent<ItemsTableLine, String> evt) -> {
            evt.getTableView().getItems().get(evt.getTablePosition().getRow())
                    .inputAProperty().setValue(evt.getNewValue().replace(",", "."));
        });
        inputBCol.setOnEditCommit((TableColumn.CellEditEvent<ItemsTableLine, String> evt) -> {
            evt.getTableView().getItems().get(evt.getTablePosition().getRow())
                    .inputBProperty().setValue(evt.getNewValue().replace(",", "."));
        });


        tv.getColumns().setAll(typeCol, inputACol, inputBCol);

        return tv;
    }

    private class EditingCell extends TableCell {
        private TextField textField;
        @Override public void startEdit() {
            if (!isEmpty()) {
                super.startEdit();
                createTextField();
                setText(null);
                setGraphic(textField);
                //setContentDisplay(ContentDisplay.GRAPHIC_ONLY); 
                Platform.runLater(() -> {//without this space erases text, f2 doesn't
                    textField.requestFocus();//also selects
                });
                if (lastKey != null) {
                    textField.setText(lastKey);
                    Platform.runLater(() -> {textField.deselect(); textField.end();});}
            }
        }
        public void commit() { commitEdit(textField.getText()); }

        @Override
        public void cancelEdit() {
            super.cancelEdit();
            try {
                setText(getItem().toString());
            } catch (Exception e) {
            }
            setGraphic(null);
        }

        @Override
        public void updateItem(Object item, boolean empty) {
            super.updateItem(item, empty);

            if (empty) {
                setText(null);
                setGraphic(null);
            } else if (isEditing()) {
                if (textField != null) {
                    textField.setText(getString());
                }
                setText(null);
                setGraphic(textField);
            } else {
                setText(getString());
                setGraphic(null);
                if (!getTableColumn().getText().equals("Name")) {
                    setAlignment(Pos.CENTER);
                }
            }
        }
        private void createTextField() {
            textField = new TextField(getString());
            textField.focusedProperty().addListener(
                    (ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) -> {
                        if (!arg2) { commitEdit(textField.getText()); }});
            textField.setOnKeyReleased((KeyEvent t) -> {
                if (t.getCode() == KeyCode.ENTER) {
                    commitEdit(textField.getText());
                    EditingCell.this.getTableView().getSelectionModel().selectBelowCell(); }
                if (t.getCode() == KeyCode.ESCAPE) { cancelEdit(); }});
            textField.addEventFilter(KeyEvent.KEY_RELEASED, (KeyEvent t) -> { 
                if (t.getCode() == KeyCode.DELETE) { t.consume();}});
        }
        private String getString() {return getItem() == null ? "" : getItem().toString();}
    }
}

package minimalexample;
import java.io.Serializable;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class ItemsTableLine implements Serializable {

    private StringProperty type;
    private StringProperty inputA;
    private StringProperty inputB;

    public StringProperty typeProperty() {return type;}
    public StringProperty inputAProperty()  {return inputA;  }
    public StringProperty inputBProperty()   {return inputB;}

    public ItemsTableLine() {
        super();
        type = new SimpleStringProperty("");
        inputA  = new SimpleStringProperty("");
        inputB   = new SimpleStringProperty("");
    }

    public ItemsTableLine(String...values) {
        this();
        type.set(values[0]);
        inputA.set(values[1]);
        inputB.set(values[2]);
    }

    // Setters required due to combobox 
    public void setType(String value) {
        type.set(value);
    }
}
package minimalexample;

public enum ItemType {
    TYPEA("A", "Type A"),
    TYPEB("B", "Type B");
    private String code;
    private String text;
    private ItemType(String code, String text) { this.code = code; this.text = text;}
    public String getCode() { return code; }
    public String getText() { return text; }
    public static ItemType getByCode(String genderCode) {
       for (ItemType g : ItemType.values()) if (g.code.equals(genderCode)) return g;
       return null;
    }
    @Override public String toString() { return this.text; }
}

代码需要一些重构,但您可以通过执行以下操作来实现您的要求:

inputACol.setCellFactory(参数->新编辑单元(){
@凌驾
public void updateItem(对象项,布尔值为空){
super.updateItem(项,空);
如果(项!=null&&!空){
ItemsTableLine数据=(ItemsTableLine)getTableView().getItems().get(getIndex());
disableProperty().bind(Bindings.createBooleanBinding)(()->
!data.typeProperty().get().equals(“A”),data.typeProperty());
}否则{
disableProperty().unbind();
}
}
});
inputBCol.setCellFactory(参数->新建编辑单元(){
@凌驾
public void updateItem(对象项,布尔值为空){
super.updateItem(项,空);
如果(项!=null&&!空){
ItemsTableLine数据=(ItemsTableLine)getTableView().getItems().get(getIndex());
disableProperty().bind(Bindings.createBooleanBinding(()->
!data.typeProperty().get().equals(“B”),data.typeProperty());
}否则{
disableProperty().unbind();
}
}
});
注意:有多种方法可以做到这一点,但在您的情况下,这似乎是最简单的方法


注意:除了绑定中使用的值之外,两个代码块都是相同的,您可以编写一个方法,将其作为输入并返回单元格工厂,而不是重复代码

有点不那么简单;)想知道为什么您的模型将类型公开为String(而不是ItemType)?使用后者,您可以摆脱编辑处理程序,只需使用ValueFactorys中的属性。此外,您还需要通过使用带有提取器的observableList,在类型更改时激发项。在其他列的单元格中,根据需要检查类型和en/disable。很难在Java=)中找到最小和有效的示例没有特别的原因说明模型为什么要公开字符串,而不是我在Java和javafx方面的有限技能。如果你能回答你的建议,这样我就可以接受了请扔掉自定义编辑单元格和编辑处理程序(前者由于具有TextFieldTableCell而不需要,后者如果模型设置正确则不需要)。实际上,这看起来像是一个建模问题:定义何时启用单元格的应该是模型(或视图包装器),而不是单元格本身(这应该尽可能简单,对逻辑没有责任,只是一个跟随其主的从机)。从模型的角度来看,inputA可能是错误的!=typeB为null…嗯…核心可能有问题,无法通过快速检查使其工作..需要在本周晚些时候挖掘..sry;)