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 {

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

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

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

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

}

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

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 ;

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

        }.start();
    });

调用 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...

Java高并发面试,14:00进去的,14:05出来了..

-EOF-