Uitableview JavaFX-使用自定义textfield tablecell删除tableview中的行
我正在实现一个自定义的可编辑文本单元格,以获取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
如果我减小窗口大小,一次只能看到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;
}
}
}
}