【问题标题】:JavaFX - deleting row in tableview with custom textfield tablecellJavaFX - 使用自定义文本字段表格单元删除表格视图中的行
【发布时间】:2018-05-18 00:31:41
【问题描述】:

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

Screenshot 1 - Tableview populated with initial values & row to be deleted is selected
Screenshot 2 - Tableview after deleting selected row
Screenshot 3 - The editable text cells in the rows below the deleted rows are updated simultaneously

如果我减小窗口大小,以便一次只能看到 3 行并点击删除按钮,则当前视图之外的可编辑单元格的值会得到上述行为。

下面是我的代码。

主要:

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

@Override
public void start(Stage primaryStage) throws Exception{
    Parent root = FXMLLoader.load(getClass().getResource("IndexIssueSample.fxml"));
    primaryStage.setTitle("Hello World");
    primaryStage.setScene(new Scene(root, 600, 575));
    primaryStage.show();
}


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

控制器:

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

自定义可编辑文本单元格:

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

FXML:

<?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>

【问题讨论】:

    标签: uitableview javafx tableview javafx-8


    【解决方案1】:

    您的EditableTextCell 没有很好地实现。在大多数情况下,不会通知索引侦听器已删除的项目。显示的项目的索引毕竟保持不变(除了那些可能变空的项目,如果没有足够的项目来填充所有单元格)。此外,当项目已经从列表中消失时,会通知ObservableList 的侦听器。您无法通过这种方式正确解除与旧项目的绑定。

    由于cellValueFactorys 返回可以写入的属性,我建议使用它们来对项目进行更改。

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

    【讨论】:

    • 谢谢@fabian。这解决了问题。
    • 注意:它改变了编辑机制脚下的数据,这是一个绝对禁止区域(有例外;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多