web-dev-qa-db-ja.com

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

}

すべてが正しいように見えますが、機能していません。最後のインデックスに新しく追加されたアイテムではなく、最初のアイテムを変更しようとしているようです。理由はわかりません。

6
karim

それはバグです。

フォーカスと編集の間に本当に恐ろしい相互作用があるようです。基本的な問題は、リストのセルがフォーカスを失うと、編集をキャンセルすることです。ボタンをクリックするとフォーカスがそのボタンに移動し、次のレンダリングPulseでリストセルがフォーカスを失ったことを確認して編集をキャンセルすると思います。リストの最初のアイテムが編集状態になっているように見える理由を完全に説明することはできませんが、個々のアイテムのフォーカスを管理するリストのfocusModelとのさらなる相互作用が原因であると思います。

本当に醜いハックの場合、AnimationTimerを使用して、追加のレンダリングフレームによるListView.edit(...)の呼び出しを遅らせます。 (慣れていない場合は、 AnimationTimer が、レンダリングパルスごとに1回呼び出されるhandle(...)メソッドを定義します。ここでは、1フレームだけカウントします次に、editを呼び出して、タイマーを停止します。)

_    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(...)を呼び出すと、より堅牢に見えます(特に、互いに等しい項目があるためです:)。

多分他の誰かがこれよりも少しきれいなものを思いつくことができます...

8
James_D

問題は、Cellを呼び出す前にeditsが更新されていないことです。セルの更新はレイアウト中に行われるため、編集を開始する前にlayoutを呼び出すと問題が解決します。

例:

@Override
public void start(Stage primaryStage) {
    ListView<String> 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();
}
6
fabian

James_Dがすでに述べたこと:editメソッドのインデックスが正しく計算されていないようです。次の例では、正しいインデックスを取得しない必要がありますが、取得します。

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<String> items = FXCollections.observableArrayList("test1", "test2");
        ListView<String> 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);
    }
}

Application

5
aw-think