Javafx Listview添加和编辑元素

javafx 文章 2022-03-02 22:57 0 全屏看文



i want to  add and edit directly an element to a 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 {

    public void start(Stage primaryStage) {
        ObservableList<String> items = FXCollections.observableArrayList("test1", "test2");
        ListView<String> list = new ListView<>(items);

        list.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {

            public ListCell<String> call(ListView<String> param) {
                return new TextFieldListCell<>(new StringConverter<String>() {

                    public String toString(String object) {
                        return object;

                    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.edit(list.getItems().size() - 1);

        VBox root = new VBox(list, btn);

        Scene scene = new Scene(root);


     * @param args the command line arguments
    public static void main(String[] args) {



Everything seems correct but that not working, it like its try to modify the first item not the newly added item in the last index, i don't know why



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

There seems to be some truly horrible interplay between focus and editing. The basic problem seems to be that when a list cell loses focus, it cancels any editing. I think that by clicking on the button, you cause the focus to shift to that button, and then on the next rendering pulse the list cell sees it has lost focus and cancels editing. I can't quite explain why the first item in the list appears to go to an editing state, but I suspect it is due to some further interaction with the list's focusModel, which manages focus of individual items.

对于一个真正难看的黑客,使用 AnimationTimer 将呼叫延迟到 ListView.edit(...)由一个额外的渲染帧。 (如果您不熟悉它,请 AnimationTimer 定义了一个句柄(...)方法,在每个渲染脉冲上调用一次;这里我只计算一帧,然后调用编辑,并停止计时器。)

For a truly ugly hack, use an AnimationTimer to delay the call to ListView.edit(...) by an additional rendering frame. (In case you're not familiar with it, an AnimationTimer defines a handle(...) method that is invoked once on each rendering pulse; here I just count one frame and then call edit, and stop the timer.)

 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 ;

            public void handle(long now) {
                frameCount++ ;
                if (frameCount > 1) {        
                    list.edit(list.getItems().size() - 1);


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

Calling scrollTo(...) with an index instead of an item seems more robust too (especially as you have items in there that are equal to each other :).)


Maybe someone else can come up with something a bit cleaner that this...