问题描述
我想在 JavaFX 中为 TableCell 使用一个类 (TextField)。该类应该被普遍使用。找了一个星期的解决方法,在网上看了各种解决方法。
我目前的问题是我可以在 TabelView 中显示数据,但是更改没有到达控制器,即没有保存在数据类中,我不知道为什么会这样,特别是因为我已经为数据选择器设计了一个类似的结构,而且效果很好。
我希望能够控制 TabelView 中的行为并且这也适用于我的类,但是如果数据没有存储在控制器的数据类中,它有什么用?
目前我可以在TabelView中看到数据类中的值并根据类中的设置对其进行编辑,但是我无法将数据导入到控制器中的数据类中。
到目前为止,这是我的方法:
控制器
columnCourse.setCellValueFactory(new PropertyValueFactory<>("CourseName"));
columnCourse.setCellFactory(i -> new CellClasstextFieldString(columnCourse,20));
columnCourse.setonEditCommit(e -> { System.out.println("Commit in Controller ");; });
TextFieldClass
public class CellClasstextFieldString<T> extends TableCell<T,String> {
private final TextField textField;
private final int maxLen;
public CellClasstextFieldString(TableColumn<T,String> stringCol,Integer maxLen) {
this.textField = new TextField();
this.maxLen = maxLen;
this.textField.settextformatter(new textformatter<>(new StringConverter<String>() {
@Override
public String toString(String object) {
if(object == null) return "";
if (object.length() > maxLen) {
return object.substring(0,maxLen);
} else {
return object;
}
}
@Override
public String fromString(String string) {
if(string == null) {
return "";
} else {
if (string.length() > maxLen) {
return string.substring(0,maxLen);
} else {
return string;
}
}
}
}));
editableproperty().bind(stringCol.editableproperty());
contentdisplayproperty().bind(Bindings
.when(editableproperty())
.then(Contentdisplay.GRAPHIC_ONLY)
.otherwise(Contentdisplay.TEXT_ONLY)
);
setListener () ;
}
@Override
protected void updateItem(String strInput,boolean empty) {
System.out.println("updateItem");
super.updateItem(strInput,empty);
if(empty) {
setText(null);
setGraphic(null);
} else {
this.textField.setText(strInput);
setGraphic(this.textField);
if(strInput == null) {
setText("");
} else {
setText(strInput);
}
}
}
private void setListener () {
this.textField.focusedproperty().addListener((observable,oldValue,newValue) -> {
if(newValue) {
System.out.println("get focus");
} else {
System.out.println("lost focus");
commitEdit(textField.getText());
}
});
this.textField.textproperty().addListener((observable,newValue) -> {
System.out.println("comit : " + newValue + "isEditing : " + isEditing());
if (newValue.length() > maxLen) {
textField.setText(oldValue);
}
});
this.textField.setonKeypressed(new EventHandler<KeyEvent>() {
@Override public void handle(KeyEvent evt) {
if (KeyCode.ESCAPE == evt.getCode()) {
System.out.println("cancel edit");
cancelEdit();
}
if (KeyCode.ENTER == evt.getCode() || KeyCode.TAB == evt.getCode() ) {
System.out.println("commit edit");
commitEdit(textField.getText());
}
}
});
}
}
解决方法
我可以清楚地注意到一个问题是 contentDisplayProperty 的绑定。是否仅在编辑时才需要 textField?如果是这种情况,您需要绑定只读编辑属性而不是可编辑属性。
contentDisplayProperty().bind(Bindings
.when(editingProperty())
.then(ContentDisplay.GRAPHIC_ONLY)
.otherwise(ContentDisplay.TEXT_ONLY)
);
以下是可以工作的修改后的单元格实现。 (至少它对我有用:-))
class CellClassTextFieldString<T> extends TableCell<T,String> {
private TextField textField;
private final int maxLen;
public CellClassTextFieldString(TableColumn<T,String> stringCol,Integer maxLen) {
this.maxLen = maxLen;
editableProperty().bind(stringCol.editableProperty());
contentDisplayProperty().bind(Bindings
.when(editingProperty())
.then(ContentDisplay.GRAPHIC_ONLY)
.otherwise(ContentDisplay.TEXT_ONLY)
);
}
@Override
protected void updateItem(String strInput,boolean empty) {
System.out.println("updateItem");
super.updateItem(strInput,empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getItem());
}
setGraphic(textField);
} else {
setText(getItem());
}
}
}
@Override
public final void cancelEdit() {
super.cancelEdit();
setText(getItem());
}
@Override
public final void commitEdit(final String newValue) {
super.commitEdit(newValue);
}
@Override
public final void startEdit() {
super.startEdit();
if (textField == null) {
createTextField();
}
setGraphic(textField);
textField.setText(getItem());
textField.selectAll();
textField.requestFocus();
}
private void createTextField() {
this.textField = new TextField();
this.textField.setTextFormatter(new TextFormatter<>(new StringConverter<String>() {
@Override
public String toString(String object) {
if (object == null) return "";
if (object.length() > maxLen) {
return object.substring(0,maxLen);
} else {
return object;
}
}
@Override
public String fromString(String string) {
if (string == null) {
return "";
} else {
if (string.length() > maxLen) {
return string.substring(0,maxLen);
} else {
return string;
}
}
}
}));
this.textField.focusedProperty().addListener((observable,oldValue,newValue) -> {
if (!newValue) {
System.out.println("lost focus");
commitEdit(textField.getText());
}
});
this.textField.textProperty().addListener((observable,newValue) -> {
if (newValue.length() > maxLen) {
textField.setText(oldValue);
}
});
this.textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent evt) {
if (KeyCode.ESCAPE == evt.getCode()) {
System.out.println("cancel edit");
cancelEdit();
}
if (KeyCode.ENTER == evt.getCode() || KeyCode.TAB == evt.getCode()) {
System.out.println("commit edit");
commitEdit(textField.getText());
}
}
});
}
}
您可以按如下方式更新您的数据:
columnCourse.setOnEditCommit(e -> {
System.out.println("Commit in Controller ");
( e.getTableView().getItems().get(
e.getTablePosition().getRow())
).set<Name>(e.getNewValue());
});