JavaFX TableView单元格TextField编辑自动补全失效求助
解决TableView编辑单元格自动提示不生效的问题
我看了你的代码,发现几个关键问题导致自动提示功能在调用learnword后没效果,下面一步步帮你解决:
核心问题分析
- 每个单元格维护独立的单词集合:你现在的
possibleWordSet是每个EditingCell实例私有的HashSet,这意味着你在A单元格输入的单词,B单元格完全看不到;而且TableView会复用单元格,之前学习的单词会随着旧单元格实例被回收而丢失。 - 手动重新绑定的时机错误:你在
learnword里dispose旧绑定再重新绑定,但此时单元格可能已经退出编辑状态,textField可能已经被销毁或隐藏,新绑定根本不会作用到后续的编辑操作中。 - 未利用Observable集合的自动更新特性:普通HashSet不会通知自动提示组件集合变化,需要手动重新绑定,这既麻烦又容易出错。
解决方案
第一步:改用全局共享的Observable集合
把单词集合改成所有单元格共享的ObservableSet,这样集合变化时自动提示组件会自动刷新,不需要手动重新绑定。比如在你的GUIFXMLDocumentController里定义全局集合:
// 在GUIFXMLDocumentController中定义全局共享的可观察单词集合 public static ObservableSet<String> possibleWordSet = FXCollections.observableSet(new HashSet<>());
第二步:修改EditingCell代码,关联全局集合
更新EditingCell的逻辑,让它使用全局集合,并简化learnword方法:
class EditingCell extends TableCell<File, String> { // 引用全局共享的可观察集合 private ObservableSet<String> possibleWordSet = GUIFXMLDocumentController.possibleWordSet; private AutoCompletionBinding<String> autoCompletionBinding; private TextField textField; @Override public void startEdit() { if (!isEmpty()) { super.startEdit(); createTextField(); setText(null); setGraphic(textField); } } @Override public void cancelEdit() { super.cancelEdit(); setText(getItem()); setGraphic(null); } @Override public void updateItem(String item, boolean empty) { super.updateItem(item, empty); if (empty) { setText(null); setGraphic(null); } else { if (isEditing()) { if (textField != null) { textField.setText(item); } setText(null); setGraphic(textField); } else { setText(item); setGraphic(null); } } } public void createTextField() { textField = new TextField(getItem()); textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2); // 绑定到全局ObservableSet,集合变化时自动提示会实时更新 autoCompletionBinding = TextFields.bindAutoCompletion(textField, possibleWordSet); textField.setOnKeyReleased(t -> { if (t.getCode() == KeyCode.ENTER) { String newText = textField.getText().trim(); commitEdit(newText); learnWord(newText); } else if (t.getCode() == KeyCode.ESCAPE) { cancelEdit(); } }); textField.setOnMouseClicked(event -> { int caretPosition = textField.getCaretPosition(); // 注意:这里new GUIFXMLDocumentController会创建新实例,建议改为获取当前控制器 // 比如通过TableView的场景获取窗口中的控制器实例 GUIFXMLDocumentController fx = new GUIFXMLDocumentController(); fx.setCaretPos(caretPosition); fx.setTextField(textField); }); textField.focusedProperty().addListener((arg0, arg1, arg2) -> { if (!arg2) { String newText = textField.getText().trim(); GUIFXMLDocumentController.tv_new.getFocusModel().focusNext(); commitEdit(newText); learnWord(newText); } }); } public void learnWord(String text) { // 仅添加非空非空白的文本到全局集合 if (text != null && !text.isEmpty()) { possibleWordSet.add(text); } // 无需手动重新绑定,ObservableSet会自动通知自动提示组件更新 } }
额外优化提示
- 你在鼠标点击事件中
new GUIFXMLDocumentController()会创建一个全新的控制器实例,这不会影响你当前界面的控制器。建议改为通过getTableView().getScene().getWindow()获取当前窗口,再从中获取正确的控制器实例。 - 如果需要持久化学习的单词,可以在程序启动时从文件加载集合,退出时保存集合。
内容的提问来源于stack exchange,提问作者Pragati Singh
相关产品推荐
相关产品推荐

