Uitableview JavaFX-使用自定义textfield tablecell删除tableview中的行

Uitableview JavaFX-使用自定义textfield tablecell删除tableview中的行,uitableview,javafx,tableview,javafx-8,Uitableview,Javafx,Tableview,Javafx 8,我正在实现一个自定义的可编辑文本单元格,以获取tableview中的选项卡功能。一切正常,但当我删除一行时,删除行下方的可编辑单元格会同时更改值。因此,键入已删除行下方的单元格将更改该列中多个单元格的项目 如果我减小窗口大小,一次只能看到3行,然后点击delete按钮,那么当前视图之外的editable cell的值就会得到上面提到的行为 下面是我的代码 主要内容: 控制器: import javafx.collections.FXCollections; import javafx.co

我正在实现一个自定义的可编辑文本单元格,以获取tableview中的选项卡功能。一切正常,但当我删除一行时,删除行下方的可编辑单元格会同时更改值。因此,键入已删除行下方的单元格将更改该列中多个单元格的项目



如果我减小窗口大小,一次只能看到3行,然后点击delete按钮,那么当前视图之外的editable cell的值就会得到上面提到的行为

下面是我的代码

主要内容:

控制器:

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import java.net.URL;
import java.util.ResourceBundle;

public class IndexIssueController implements Initializable {
@FXML
private TableView<Person> personTableView;

@FXML
private TableColumn<Person, String> someDataColumn;

@FXML
private TableColumn<Person, String> someMoreDataColumn;

@FXML
private TableColumn<Person, String> additionalDataColumn;

Person person = new Person();

@Override
public void initialize(URL location, ResourceBundle resources) {
    someDataColumn.setCellValueFactory(new PropertyValueFactory<>("someData"));
    someMoreDataColumn.setCellValueFactory(new PropertyValueFactory<>("someMoreData"));
    ObservableList<Person> personObservableList = FXCollections.observableArrayList();
    additionalDataColumn.setCellValueFactory(new PropertyValueFactory<>("additionalData"));
    someDataColumn.setCellFactory(e -> new EditableTextCell(0));
    someMoreDataColumn.setCellFactory(e -> new EditableTextCell(1));
    Person initPerson = setUpPersonData();
    Person personData1 = null, personData2 = null, personData3 = null, personData4 = null, personData5 = null, personData6 = null;
    try {
        personData1 = (Person) initPerson.clone();
        personData2 = (Person) initPerson.clone();
        personData3 = (Person) initPerson.clone();
        personData4 = (Person) initPerson.clone();
        personData5 = (Person) initPerson.clone();
        personData6 = (Person) initPerson.clone();
        personData1.setSomeData("1");
        personData1.setSomeMoreData("a");
        personData2.setSomeData("2");
        personData2.setSomeMoreData("b");
        personData3.setSomeData("3");
        personData3.setSomeMoreData("c");
        personData4.setSomeData("4");
        personData4.setSomeMoreData("d");
        personData5.setSomeData("5");
        personData5.setSomeMoreData("e");
        personData6.setSomeData("6");
        personData6.setSomeMoreData("f");
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
    personObservableList.addAll(personData1, personData2, personData3, personData4, personData5, personData6);
    personTableView.setItems(personObservableList);
    personTableView.getSelectionModel().setCellSelectionEnabled(true);
}

private Person setUpPersonData() {
    try {
        person.setSomeData("This is SomeData");
        person.setSomeMoreData("This is SomeMoreDate");
        person.setAdditionalData("This is AdditionalData");
    } catch (Exception e1) {
        e1.printStackTrace();
    }
    return person;
}

@FXML
public void deleteRowButtonPushed(){
    personTableView.getItems().remove(personTableView.getSelectionModel().getSelectedItem());
}
}
FXML:


您的
EditableTextCell
没有很好地实现。在大多数情况下,不会通知索引侦听器已删除的项。显示的项目索引始终保持不变(如果没有足够的项目填充所有单元格,则可能变为空的项目除外)。此外,当项目已从列表中删除时,将通知
可观察列表的侦听器。这样无法正确解除与旧项的绑定

由于
cellValueFactory
返回可以写入的属性,因此我建议使用它们来更改项目

public class EditableTextCell<E> extends TableCell<E, String> {

    private final TextField textField;
    private boolean updating = false;

    public EditableTextCell() {
        textField = new TextField();
        textField.textProperty().addListener((o, oldValue, newValue) -> {
            if (!updating) {
                ((WritableValue<String>) getTableColumn().getCellObservableValue((E) getTableRow().getItem())).setValue(newValue);
            }
        });
    }

    @Override
    protected void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        if (empty) {
            setGraphic(null);
        } else {
            setGraphic(textField);
            if (!Objects.equals(textField.getText(), item)) { // prevent own updates from moving the cursor
                updating = true;
                textField.setText(item);
                updating = false;
            }
        }
    }
}
公共类EditableTextCell扩展了TableCell{
私有最终文本字段文本字段;
私有布尔更新=false;
公共EditableTextCell(){
textField=新的textField();
textField.textProperty().addListener((o,oldValue,newValue)->{
如果(!正在更新){
((WritableValue)getTableColumn().getCellObservableValue((E)getTableRow().getItem()).setValue(newValue);
}
});
}
@凌驾
受保护的void updateItem(字符串项,布尔值为空){
super.updateItem(项,空);
if(空){
设置图形(空);
}否则{
设置图形(文本字段);
如果(!Objects.equals(textField.getText(),item)){//阻止自己的更新移动光标
更新=真;
textField.setText(项目);
更新=假;
}
}
}
}

谢谢@fabian。这解决了这个问题。注意:它会更改编辑机制下的数据,这是一个绝对禁止进入的区域(例外;)
import javafx.collections.ObservableList;
import javafx.scene.control.*;

class EditableTextCell extends TableCell<Person, String> {
private final TextField textField;
    EditableTextCell(int columnIndex) {

        textField = new TextField();

        this.indexProperty().addListener((obs, oldValue, newValue) -> {
                ObservableList<Person> tableData = getTableView().getItems();
                int oldIndex = oldValue.intValue();
                if (oldIndex >= 0 && oldIndex < tableData.size()) {
                    if (columnIndex == 0)
                        textField.textProperty().unbindBidirectional(tableData.get(oldIndex).someDataProperty());
                    if (columnIndex == 1)
                        textField.textProperty().unbindBidirectional(tableData.get(oldIndex).someMoreDataProperty());
                }
                int newIndex = newValue.intValue();
                if (newIndex >= 0 && newIndex < tableData.size()) {
                    if(columnIndex == 0){
                        textField.textProperty().bindBidirectional(tableData.get(newIndex).someDataProperty());
                        //System.out.println("Printing value for newIndex " + newIndex + " someData textField " + textField.getText() + " someDataProperty " + tableData.get(newIndex).someDataProperty().getValue());
                    }
                    if(columnIndex == 1){
                        textField.textProperty().bindBidirectional(tableData.get(newIndex).someMoreDataProperty());
                        //System.out.println("Printing value for newIndex " + newIndex + " someMoreData textField " + textField.getText()+ " someMoreDataProperty " + tableData.get(newIndex).someMoreDataProperty().getValue());
                    }
                    setGraphic(textField);
                } else {
                    setGraphic(null);
                }
        });
    }
}
import javafx.beans.property.SimpleStringProperty;
public class Person {
private SimpleStringProperty someData, someMoreData, additionalData;

public Person() {
    this.someData = new SimpleStringProperty("");
    this.someMoreData = new SimpleStringProperty("");
    this.additionalData = new SimpleStringProperty("");
}

public Person(String someData, String someMoreData, String additionalData) {
    this.someData = new SimpleStringProperty(someData);
    this.someMoreData = new SimpleStringProperty(someMoreData);
    this.additionalData = new SimpleStringProperty(additionalData);
}

@Override
public Object clone()throws CloneNotSupportedException{
    String someDataCloned = this.someData.getValue();
    String someMoreDataCloned = this.someMoreData.getValue();
    String additionalDataCloned = this.additionalData.getValue();
    Person personCloned = new Person(someDataCloned, someMoreDataCloned, additionalDataCloned);
    return personCloned;
}

public String getSomeData() {
    return someData.get();
}

public SimpleStringProperty someDataProperty() {
    return someData;
}

public void setSomeData(String someData) {
    this.someData.set(someData);
}

public String getSomeMoreData() {
    return someMoreData.get();
}

public SimpleStringProperty someMoreDataProperty() {
    return someMoreData;
}

public void setSomeMoreData(String someMoreData) {
    this.someMoreData.set(someMoreData);
}

public String getAdditionalData() {
    return additionalData.get();
}

public SimpleStringProperty additionalDataProperty() {
    return additionalData;
}

public void setAdditionalData(String additionalData) {
    this.additionalData.set(additionalData);
}
}
<?xml version="1.0" encoding="UTF-8"?>

<?import com.jfoenix.controls.JFXButton?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane prefHeight="400.0" prefWidth="1250.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.IndexIssueController">
<children>
    <TableView fx:id="personTableView" layoutY="50.0" AnchorPane.bottomAnchor="50.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
        <columns>
            <TableColumn fx:id="someDataColumn" prefWidth="84.0" text="Some Data" />
            <TableColumn fx:id="someMoreDataColumn" minWidth="100.0" prefWidth="100.0" text="Some More Data" />
            <TableColumn fx:id="additionalDataColumn" minWidth="150.0" prefWidth="150.0" text="Additional Data" />
        </columns>
    </TableView>
  <JFXButton fx:id="deleteRowButton" layoutX="14.0" layoutY="363.0" onAction="#deleteRowButtonPushed" style="-fx-background-color: #0097db;" text="Delete Row" textFill="WHITE" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0">
     <font>
        <Font name="Arial" size="12.0" />
     </font>
  </JFXButton>
</children>
</AnchorPane>
public class EditableTextCell<E> extends TableCell<E, String> {

    private final TextField textField;
    private boolean updating = false;

    public EditableTextCell() {
        textField = new TextField();
        textField.textProperty().addListener((o, oldValue, newValue) -> {
            if (!updating) {
                ((WritableValue<String>) getTableColumn().getCellObservableValue((E) getTableRow().getItem())).setValue(newValue);
            }
        });
    }

    @Override
    protected void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        if (empty) {
            setGraphic(null);
        } else {
            setGraphic(textField);
            if (!Objects.equals(textField.getText(), item)) { // prevent own updates from moving the cursor
                updating = true;
                textField.setText(item);
                updating = false;
            }
        }
    }
}