Javafx Listview添加和编辑元素

我想直接添加和编辑一个元素到listview:

/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package javafx_test; import java.util.Observable; import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; import javafx.scene.control.cell.TextFieldListCell; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.stage.Stage; import javafx.util.Callback; import javafx.util.StringConverter; /** * * @author karim */ public class Javafx_test extends Application { @Override public void start(Stage primaryStage) { ObservableList items = FXCollections.observableArrayList("test1", "test2"); ListView list = new ListView(items); list.setEditable(true); list.setCellFactory(new Callback<ListView, ListCell>() { @Override public ListCell call(ListView param) { return new TextFieldListCell(new StringConverter() { @Override public String toString(String object) { return object; } @Override public String fromString(String string) { return string; } }); } }); Button btn = new Button(); btn.setText("Add String"); btn.setOnAction((ActionEvent event) -> { String c = new String("test"); list.getItems().add(list.getItems().size(), c); list.scrollTo(c); list.edit(list.getItems().size() - 1); }); VBox root = new VBox(list, btn); Scene scene = new Scene(root); primaryStage.setTitle("test!"); primaryStage.setScene(scene); primaryStage.show(); } /** * @param args the command line arguments */ public static void main(String[] args) { launch(args); } } 

一切似乎都是正确但不起作用,就像它尝试修改第一个项目而不是最后一个索引中新添加的项目,我不知道为什么

这是一个错误。

焦点和编辑之间似乎有一些真正可怕的相互作用。 基本问题似乎是当列表单元格失去焦点时,它会取消任何编辑。 我认为通过单击按钮,您可以使焦点移动到该按钮,然后在下一个渲染脉冲上,列表单元看到它已失去焦点并取消编辑。 我无法解释为什么列表中的第一项似乎进入编辑状态,但我怀疑这是由于与列表的focusModel进行了一些进一步的交互,后者管理各个项目的焦点。

对于一个真正丑陋的黑客,使用AnimationTimer通过一个额外的渲染帧延迟对ListView.edit(...)的调用。 (如果你不熟悉它,一个AnimationTimer定义一个handle(...)方法,在每个渲染脉冲上调用一次;这里我只计算一帧,然后调用编辑,并停止计时器。)

  btn.setOnAction((ActionEvent event) -> { String c = "test"+(list.getItems().size()+1); list.getItems().add(list.getItems().size(), c); list.scrollTo(list.getItems().size() - 1); // list.edit(list.getItems().size() - 1); new AnimationTimer() { int frameCount = 0 ; @Override public void handle(long now) { frameCount++ ; if (frameCount > 1) { list.edit(list.getItems().size() - 1); stop(); } } }.start(); }); 

使用索引而不是项目调用scrollTo(...)似乎也更健壮(特别是当你在那里有相同的项目:)时。)

也许其他人可以想出一些比这更清洁的东西……

James_D已经提到过:似乎编辑方法的索引计算错误。 在下面的示例中,它不应该获取正确的索引,但确实如此。

 import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.ListView; import javafx.scene.control.cell.TextFieldListCell; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class ListEdit extends Application { int i = 3; @Override public void start(Stage primaryStage) { ObservableList items = FXCollections.observableArrayList("test1", "test2"); ListView list = new ListView<>(items); list.setCellFactory(TextFieldListCell.forListView()); list.setEditable(true); Button btn = new Button(); btn.setText("Add String"); btn.setOnAction((ActionEvent event) -> { list.getItems().add(i - 1, "test" + i); list.edit(i - 2); i++; }); VBox root = new VBox(list, btn); Scene scene = new Scene(root); primaryStage.setTitle("test!"); primaryStage.setScene(scene); primaryStage.show(); } public static void main(String[] args) { launch(args); } } 

应用

问题似乎是在调用edit之前Cell没有被更新。 由于更新单元格是在布局期间完成的,因此在开始编辑之前调用layout应该可以解决问题:

例:

 @Override public void start(Stage primaryStage) { ListView listView = new ListView<>(); listView.setEditable(true); listView.setCellFactory(TextFieldListCell.forListView()); Button editButton = new Button("Add & Edit"); editButton.setOnAction((ActionEvent event) -> { listView.getItems().add(""); listView.scrollTo(listView.getItems().size() - 1); listView.layout(); listView.edit(listView.getItems().size() - 1); }); Scene scene = new Scene(new VBox(listView, editButton)); primaryStage.setScene(scene); primaryStage.show(); }