为TableView单个单元格设置禁用属性

问题描述 投票:0回答:1

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

这是我的情况:一列具有ComboBoxTableCell,并且根据所选择的项目,同一行中的某些单元格将被禁用。

例如:

disable Input A or B depending on Type

如果我选择类型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();
    }
}

ItemsTable.java

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();}
    }
}

ItemsTableLine.java

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);
    }
}

ItemsType.java

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; }
}
java uitableview javafx tableview tablecell
1个回答
1
投票

该代码需要进行一些重构,但是您可以通过执行以下操作来实现所需的内容:

inputACol.setCellFactory(param -> new EditingCell() {
    @Override
    public void updateItem(Object item, boolean empty) {
        super.updateItem(item, empty);
        if (item != null && !empty) {
            ItemsTableLine data = (ItemsTableLine) getTableView().getItems().get(getIndex());
            disableProperty().bind(Bindings.createBooleanBinding(() ->
                    !data.typeProperty().get().equals("A"), data.typeProperty()));
        } else {
            disableProperty().unbind();
        }
    }
});
inputBCol.setCellFactory(param -> new EditingCell() {
    @Override
    public void updateItem(Object item, boolean empty) {
        super.updateItem(item, empty);
        if (item != null && !empty) {
            ItemsTableLine data = (ItemsTableLine) getTableView().getItems().get(getIndex());
            disableProperty().bind(Bindings.createBooleanBinding(() ->
                    !data.typeProperty().get().equals("B"), data.typeProperty()));
        } else {
            disableProperty().unbind();
        }
    }
});

:这样做的方法不止一种,但是对于您来说,这似乎是最简单的。

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

© www.soinside.com 2019 - 2024. All rights reserved.