setOnEditCommit JavaFX 后禁用 TableCell

disable TableCell after setOnEditCommit JavaFX

我创建了一个 editable table,它有一个特定的列 (quantityColumn),当 setOnEditCommit 完成时,只有该列的单元格应该被禁用,而不是 editable。所以换句话说,他们只能进入一次。该程序有一个添加行按钮,可以将新行添加到 table 并且 setOnEditCommit 使用每列中每个单元格的新值更新数据库。

一个 示例 我的代码的样子:

public class TableViewController implements Initializable {

/**
 * Initializes the controller class.
 */
private Connection c = ConnectDB.getInstance().getConnection(); // ConnectDB is a helper that connects to the database
@FXML
private TableView<Item> table;

@FXML
private TableColumn<Item, LocalDate> dateColumn;

@FXML
private TableColumn<Item, LocalTime> timeColumn;

@FXML
private TableColumn<Item, String> quantityColumn;

@Override
public void initialize(URL url, ResourceBundle rb) {


 //the following three are custom TableCell classes that allows me to make my cell have a JFX date and time picker.

    Callback<TableColumn<Item, LocalDate>, TableCell<Item, LocalDate>> cellFactoryDate = 
            (TableColumn<Item, LocalDate> param) -> new DatePickerCell();
    Callback<TableColumn<Item, LocalTime>, TableCell<Item, LocalTime>> cellFactoryTime = 
            (TableColumn<Item, LocalTime> param) -> new TimePickerCell();
    Callback<TableColumn<Item, String>, TableCell<Item, String>> cellFactoryText = 
            (TableColumn<Item, String> param) -> new JFXTextFieldCell(); 


    dateColumn.setCellValueFactory(cellData -> cellData.getValue().weekDateProperty());
    timeColumn.setCellValueFactory(cellData -> cellData.getValue().timeProperty());
    quantityColumn.setCellValueFactory(cellData -> cellData.getValue().quantityProperty());

    dateColumn.setCellFactory(cellFactoryDate);
    timeColumn.setCellFactory(cellFactoryTime);   
    quantityColumn.setCellFactory(cellFactoryText);   

    table.setEditable(true);

    dateColumn.setOnEditCommit(event -> {
        Item user = event.getRowValue();
        user.setWeekDate(event.getNewValue());
        updateDate("WeekDate", event.getNewValue(), user.getID());
    });
    timeColumn.setOnEditCommit(event -> {
        Item user = event.getRowValue();
        user.setTime(event.getNewValue());
        updateTime("Time", event.getNewValue(),  user.getID());
    });
    quantityColumn.setOnEditCommit(event -> {
        Item user = event.getRowValue();
        user.setQuantity(event.getNewValue());
        updateQuantity("Quantity", event.getNewValue(),  user.getID());

        //I want to disable the cell that has been committed here
    });

}

private void updateDate(String column, LocalDate date, int id) {

    try {

        PreparedStatement stmt = c.prepareStatement("UPDATE Items SET "+column+" = ? WHERE ID = ? ");
        stmt.setDate(1, java.sql.Date.valueOf(date));
        stmt.setInt(2, id);
        stmt.executeUpdate();
    } catch (SQLException ex) {
        System.err.println("Error");
        ex.printStackTrace(System.err);
    }
}

private void updateTime(String column, LocalTime time, int id) {

    try {

        PreparedStatement stmt = c.prepareStatement("UPDATE Items SET "+column+" = ? WHERE ID = ? ");
        stmt.setTime(1, java.sql.Time.valueOf(time));
        stmt.setInt(2, id);
        stmt.executeUpdate();
    } catch (SQLException ex) {
        System.err.println("Error");
        ex.printStackTrace(System.err);
    }
}

private void updateQuantity(String column, String quantity, int id) {

    try {

        PreparedStatement stmt = c.prepareStatement("UPDATE Items SET "+column+" = ? WHERE ID = ? ");
        stmt.setString(1, quantity);
        stmt.setInt(2, id);
        stmt.executeUpdate();
    } catch (SQLException ex) {
        System.err.println("Error");
        ex.printStackTrace(System.err);
    }
}
 @FXML
 private void addRow(ActionEvent event) {

    // get current position
    TablePosition pos = table.getFocusModel().getFocusedCell();

    // clear current selection
    table.getSelectionModel().clearSelection();

    // create new record and add it to the model
    Item data = new Item();
    table.getItems().add(data);
    // get last row
    int row = table.getItems().size() - 1;
    table.getSelectionModel().select( row, pos.getTableColumn());

    // scroll to new row
    table.scrollTo( data);

 }

}

项目:

public class Item {

private final IntegerProperty id;
private final ObjectProperty<LocalDate> weekDate;
private final ObjectProperty<LocalTime> time;
private final StringProperty quantity;


public Item() {
    this(0, null, null, null);
}
/**
 * Constructor with some initial data.
 * @param id
 * @param weekDate
 * @param time
 * @param quantity
 * 
 */
public Item(int id, LocalDate weekDate, LocalTime time, String quantity) {            
    this.id = new SimpleIntegerProperty(id);
    this.weekDate = new SimpleObjectProperty(weekDate);
    this.time = new SimpleObjectProperty(time);
    this.quantity = new SimpleStringProperty(quantity);

}


public int getID() {
    return id.get();
}

public void setID(int id) {
    this.id.set(id);
}

public IntegerProperty idProperty() {
    return id;
}

public LocalDate getWeekDate() {
    return weekDate.get();
}

public void setWeekDate(LocalDate weekDate) {
    this.weekDate.set(weekDate);
}

public ObjectProperty<LocalDate> weekDateProperty() {
    return weekDate;
}


public LocalTime getTime() {
    return time.get();
}

public void setTime(LocalTime time) {
    this.time.set(time);
}

public ObjectProperty<LocalTime> timeProperty() {
    return time;
}

public String getQuantity() {
    return quantity.get();
}

public void setQuantity(String quantity) {
    this.quantity.set(quantity);
}

public StringProperty quantityProperty() {
    return quantity;
}
}

TableView FXML

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="disablecelltest.TableViewController">
   <children>
      <TableView fx:id="table" editable="true" layoutX="61.0" layoutY="70.0" prefHeight="292.0" prefWidth="479.0">
        <columns>
          <TableColumn fx:id="dateColumn" prefWidth="75.0" text="Date" />
          <TableColumn fx:id="timeColumn" prefWidth="75.0" text="Time" />
            <TableColumn fx:id="quantityColumn" prefWidth="75.0" text="Quantity" />
        </columns>
      </TableView>
      <JFXButton buttonType="RAISED" contentDisplay="TEXT_ONLY" graphicTextGap="10.0" layoutX="10.0" layoutY="10.0" onAction="#addRow" text="ADD RECORD" textAlignment="CENTER">
         <font>
            <Font name="Dosis SemiBold" size="18.0" />
         </font>
      </JFXButton>
   </children>
</AnchorPane>

我试过在这里寻找答案。这也是one answer I tried and modified it without condition it disabled the whole column not that certain cell as I don't have a condition for the item I just want to disable when its been entered only once. I tried this

编辑: 这是我用于数量的自定义 JFXTextField:

public class JFXTextFieldCell extends TableCell<Item, String> {

        private JFXTextField textField;

        public JFXTextFieldCell() {
        }

        @Override
        public void startEdit() {
            if (!isEmpty()) {
                super.startEdit();
                createTextField();
                setText(null);
                setGraphic(textField);
                textField.selectAll();
            }
        }

        @Override
        public void cancelEdit() {
            super.cancelEdit();

            setText((String) getItem());
            setGraphic(null);
        }

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

            if (empty) {
                setText(item);
                setGraphic(null);
            } else {
                if (isEditing()) {
                    if (textField != null) {
                        textField.setText(getString());
//                        setGraphic(null);
                    }
                    setText(null);
                    setGraphic(textField);
                } else {
                    setText(getString());
                    setGraphic(null);
                }
            }
        }

        private void createTextField() {
            textField = new JFXTextField(getString());
            textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
            textField.setOnAction((e) -> commitEdit(textField.getText()));
            textField.focusedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
                if (!newValue) {
                    commitEdit(textField.getText());
                }
            });
        }

        private String getString() {
            return getItem() == null ? "" : getItem();
        }
}

简单地禁用(或使 uneditable)当前单元格不起作用;细胞将被重新分配,例如如果用户在 table 周围滚动,那么错误的单元格最终将不是 editable。

您将需要向您的模型添加一些 属性(或在其他地方存储一些可以通过模型实例访问的属性)并实现一个观察这些属性的自定义单元格,更新 editable 适当说明。

像下面这样的东西应该可以工作:

ObservableSet<Item> quantityEditedItems = FXCollections.observableSet();

quantityColumn.setCellFactory(tc -> new TextFieldTableCell<>(new IntegerStringConverter()) {
    @Override
    public void updateItem(Integer quantity, boolean empty) {
        super.updateItem(quantity, empty) ;
        editableProperty().unbind();
        if (empty) {
            setEditable(false);
        } else {
            editableProperty().bind(Bindings.createBooleanBinding(() ->
                ! quantityEditedItems.contains(getTableView().getItems().get(getIndex())),
                quantityEditedItems));
        }
    }
});

然后你可以做

quantityColumn.setOnEditCommit(event -> {
    StudentPresc user = event.getRowValue(); // should this be Item?
    user.setQuantity(event.getNewValue());
    updateQuantity("Quantity", event.getNewValue(),  user.getID());

    quantityEditedItems.add(event.getRowValue());
});

这是一个完整的工作示例:

import java.util.Random;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;
import javafx.collections.SetChangeListener.Change;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.converter.IntegerStringConverter;

public class EditOnceTable extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        TableView<Item> table = new TableView<>();
        table.setEditable(true);
        TableColumn<Item, String> itemColumn = new TableColumn<>("Item");
        itemColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty());

        TableColumn<Item, Integer> quantityColumn = new TableColumn<>("Quantity");
        quantityColumn.setCellValueFactory(cellData -> cellData.getValue().quantityProperty().asObject());
        quantityColumn.setEditable(true);

        table.getColumns().add(itemColumn);
        table.getColumns().add(quantityColumn);

        ObservableSet<Item> quantityEditedItems = FXCollections.observableSet();

        quantityColumn.setCellFactory(tc -> new TextFieldTableCell<>(new IntegerStringConverter()) {
            @Override
            public void updateItem(Integer quantity, boolean empty) {
                super.updateItem(quantity, empty) ;
                editableProperty().unbind();
                if (empty) {
                    setEditable(false);
                } else {
                    editableProperty().bind(Bindings.createBooleanBinding(() ->
                        ! quantityEditedItems.contains(getTableView().getItems().get(getIndex())),
                        quantityEditedItems));
                }
            }
        });

        quantityColumn.setOnEditCommit(event -> {
            Item item = event.getRowValue(); // should this be Item?
            item.setQuantity(event.getNewValue());
//          updateQuantity("Quantity", event.getNewValue(),  user.getID());

            quantityEditedItems.add(event.getRowValue()) ;
        });

        ListView<Item> editedItemsView = new ListView<>();
        quantityEditedItems.addListener((Change<? extends Item> change) -> 
            editedItemsView.getItems().setAll(quantityEditedItems)
        );
        editedItemsView.setCellFactory(lv -> new ListCell<>() {
            @Override
            protected void updateItem(Item item, boolean empty) {
                super.updateItem(item, empty);
                if (empty || item==null) {
                    setText("");
                } else {
                    setText(item.getName());
                }
            }
        });
        Button clear = new Button("Clear edited");
        clear.setOnAction(e -> quantityEditedItems.clear());

        Random rng = new Random();
        for (int i = 1 ; i <= 40 ; i++) {
            table.getItems().add(new Item("Item "+i, rng.nextInt(100)));
        }

        BorderPane root = new BorderPane(table);
        root.setRight(new VBox(5, new Label("Edited:"), editedItemsView, clear));

        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }


    public static class Item {
        private final StringProperty name = new SimpleStringProperty() ;
        private final IntegerProperty quantity = new SimpleIntegerProperty();

        public Item(String name, int quantity) {
            setName(name);
            setQuantity(quantity);
        }

        public StringProperty nameProperty() {
            return name ;
        }

        public final String getName() {
            return nameProperty().get();
        }

        public final void setName(String name) {
            nameProperty().set(name);
        }

        public IntegerProperty quantityProperty() {
            return quantity ;
        }

        public final int getQuantity() {
            return quantityProperty().get();
        }

        public final void setQuantity(int quantity) {
            quantityProperty().set(quantity);
        }
    }

    public static void main(String[] args) {
        Application.launch(args);
    }

}