1

UITableView - Better Editing through Binding?で概説されているソリューションを変更しようとしています。(jKaufmann さん、素晴らしい例をありがとう) テーブルに行を追加できるようにします。

クリックすると、コードを呼び出して、テーブルを裏付ける ObservableList に追加の TableData 行を追加するボタンを導入しました。

新しい行は問題なく表示されます。ただし、いくつかの行が追加され、上/下キーを数回使用してテーブルをスクロールすると、テーブル内のランダムな行が空白行に置き換えられ始めます。

通常、いくつかの行を追加し、行を選択し、(キーボードを使用して) リストを下に移動して新しい行に移動し、さらにいくつかの行を追加して、新しい行に移動し、もう一度一番上まで移動して、問題。テーブル内の行を選択するには、行の端をクリックして、個々のセルではなく行が選択されるようにします。

ソース コード (基本的に、[行の追加] ボタンを含めるように変更された jkaufmann の例) はこちらです。

package tablevieweditingwithbinding;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Callback;

public class TableViewEditingExample2 extends Application {

    public static class TableData {

        private SimpleStringProperty firstName, lastName, phone, email;
        private ObjectProperty<SimpleStringProperty> firstNameObject;

        public TableData(String firstName, String lastName, String phone, String email) {
            this.firstName = new SimpleStringProperty(firstName);
            this.firstNameObject = new SimpleObjectProperty(firstNameObject);
            this.lastName = new SimpleStringProperty(lastName);
            this.phone = new SimpleStringProperty(phone);
            this.email = new SimpleStringProperty(email);
        }

        public String getEmail() {
            return email.get();
        }

        public void setEmail(String email) {
            this.email.set(email);
        }

        public SimpleStringProperty emailProperty() {
            return email;
        }

        public String getFirstName() {
            return firstName.get();
        }

        public SimpleStringProperty getFirstNameObject() {
            return firstNameObject.get();
        }

        public void setFirstNameObject(SimpleStringProperty firstNameObject) {
            this.firstNameObject.set(firstNameObject);
        }

        public ObjectProperty<SimpleStringProperty> firstNameObjectProperty() {
            return firstNameObject;
        }

        public void setFirstName(String firstName) {
            this.firstName.set(firstName);
        }

        public SimpleStringProperty firstNameProperty() {
            return firstName;
        }

        public String getLastName() {
            return lastName.get();
        }

        public void setLastName(String lastName) {
            this.lastName.set(lastName);
        }

        public SimpleStringProperty lastNameProperty() {
            return lastName;
        }

        public String getPhone() {
            return phone.get();
        }

        public void setPhone(String phone) {
            this.phone.set(phone);
        }

        public SimpleStringProperty phoneProperty() {
            return phone;
        }
    }

    public static class TextFieldCellFactory
            implements Callback<TableColumn<TableData, String>, TableCell<TableData, String>> {

        @Override
        public TableCell<TableData, String> call(TableColumn<TableData, String> param) {
            TextFieldCell textFieldCell = new TextFieldCell();
            return textFieldCell;
        }

        public static class TextFieldCell extends TableCell<TableData, String> {

            private TextField textField;
            private StringProperty boundToCurrently = null;

            public TextFieldCell() {
                String strCss;
                // Padding in Text field cell is not wanted - we want the Textfield itself to "be"
                // The cell.  Though, this is aesthetic only.  to each his own.  comment out
                // to revert back.  
                strCss = "-fx-padding: 0;";
                textField = new TextField();

                // 
                // Default style pulled from caspian.css. Used to play around with the inset background colors
                // ---trying to produce a text box without borders
                strCss = ""
                        + //"-fx-background-color: -fx-shadow-highlight-color, -fx-text-box-border, -fx-control-inner-background;" +
                        "-fx-background-color: transparent;"
                        + //"-fx-background-insets: 0, 1, 2;" +
                        //"-fx-background-insets: 0;" +
                        //"-fx-background-radius: 3, 2, 2;" +
                        //"-fx-background-radius: 0;" +
                        //"-fx-padding: 3 5 3 5;" +   /*Play with this value to center the text depending on cell height??*/
                        //"-fx-padding: 0 0 0 0;" +
                        //"-fx-prompt-text-fill: derive(-fx-control-inner-background,-30%);" +
                        //"-fx-accent: derive(-fx-control-inner-background, -40%);" +
                        "-fx-cell-hover-color: derive(-fx-control-inner-background, -20%);"
                        + "-fx-cursor: text;"
                        + "";

                // 
                textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
                    public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                        TextField tf = (TextField) getGraphic();
                        String strStyleGotFocus = "-fx-background-color: purple, -fx-text-box-border, -fx-control-inner-background;"
                                + "-fx-background-insets: -0.4, 1, 2;"
                                + "-fx-background-radius: 3.4, 2, 2;";
                        String strStyleLostFocus = //"-fx-background-color: -fx-shadow-highlight-color, -fx-text-box-border, -fx-control-inner-background;" +
                                "-fx-background-color: transparent;"
                                + //"-fx-background-insets: 0, 1, 2;" +
                                "-fx-background-insets: 0;"
                                + //"-fx-background-radius: 3, 2, 2;" +
                                "-fx-background-radius: 0;"
                                + "-fx-padding: 3 5 3 5;"
                                + /**/ //"-fx-background-fill: green;" +   /**/
                                //"-fx-background-color: green;" +
                                "-fx-background-opacity: 0;"
                                + //"-fx-opacity: 0;" +
                                //"-fx-padding: 0 0 0 0;" +
                                "-fx-prompt-text-fill: derive(-fx-control-inner-background,-30%);"
                                + "-fx-cursor: text;"
                                + "";

                        if (newValue.booleanValue()) {
                            tf.setStyle(strStyleGotFocus);
                        } else {
                            tf.setStyle(strStyleLostFocus);
                        }

                    }
                });
                textField.setStyle(strCss);
                this.setGraphic(textField);
            }

            @Override
            protected void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);
                if (!empty) {
                    // Show the Text Field
                    this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);

                    // Retrieve the actual String Property that should be bound to the TextField
                    // If the TextField is currently bound to a different StringProperty
                    // Unbind the old property and rebind to the new one
                    ObservableValue<String> ov = getTableColumn().getCellObservableValue(getIndex());
                    SimpleStringProperty sp = (SimpleStringProperty) ov;

                    if (this.boundToCurrently == null) {
                        this.boundToCurrently = sp;
                        this.textField.textProperty().bindBidirectional(sp);
                    } else {
                        if (this.boundToCurrently != sp) {
                            this.textField.textProperty().unbindBidirectional(this.boundToCurrently);
                            this.boundToCurrently = sp;
                            this.textField.textProperty().bindBidirectional(this.boundToCurrently);
                        }
                    }
                    System.out.println("item=" + item + " ObservableValue<String>=" + ov.getValue());
                } else {
                    this.setContentDisplay(ContentDisplay.TEXT_ONLY);
                }
            }
        }
    }
    private final TableView<TableData> table = new TableView<TableData>();
    final ObservableList<TableData> ol =
            FXCollections.observableArrayList(
            new TableData("Wilma", "Flintstone", "555-123-4567", "WFlintstone@gmail.com"),
            new TableData("Fred", "Flintstone", "555-123-4567", "FFlintstone@gmail.com"),
            new TableData("Barney", "Flintstone", "555-123-4567", "Barney@gmail.com"),
            new TableData("Bugs", "Bunny", "555-123-4567", "BugsB@gmail.com"),
            new TableData("Yo", "Sam", "555-123-4567", "ysam@gmail.com"),
            new TableData("Tom", "", "555-123-4567", "tom@gmail.com"),
            new TableData("Jerry", "", "555-123-4567", "Jerry@gmail.com"),
            new TableData("Peter", "Pan", "555-123-4567", "Ppan@gmail.com"),
            new TableData("Daffy", "Duck", "555-123-4567", "dduck@gmail.com"),
            new TableData("Tazmanian", "Devil", "555-123-4567", "tdevil@gmail.com"),
            new TableData("Mickey", "Mouse", "555-123-4567", "mmouse@gmail.com"),
            new TableData("Mighty", "Mouse", "555-123-4567", "mimouse@gmail.com"));

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Application.launch(args);
    }
    static int counter = 1;

    @Override
    public void start(Stage Stage) {
        Stage.setTitle("Editable Table");
        BorderPane borderPane = new BorderPane();
        Scene scene = new Scene(borderPane, 800, 600);

        // top of border pane
        Button b1 = new Button("Change value in table list");
        Button b2 = new Button("Add row");
        HBox hbox = new HBox(10);
        hbox.setStyle("-fx-background-color: #336699");
        hbox.setAlignment(Pos.BOTTOM_CENTER);
        HBox.setMargin(b2, new Insets(10, 0, 10, 0));
        HBox.setMargin(b1, new Insets(10, 0, 10, 0));
        hbox.getChildren().addAll(b1, b2);
        borderPane.setTop(hbox);
        BorderPane.setAlignment(hbox, Pos.CENTER);

        // Button Events
        b1.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                String curFirstName = ol.get(0).getFirstName();
                if (curFirstName.contentEquals("Jason")) {
                    ol.get(0).setFirstName("Paul");
                } else {
                    ol.get(0).setFirstName("Jason");
                }
            }
        });

        b2.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        int dataListSize = 0;
                        dataListSize = ol.size();
                        System.out.println("Table size = " + dataListSize);
                        ol.add(new TableData("firstName" + counter,
                                "lastName" + counter,
                                "phone" + counter,
                                "email" + counter++));
                        dataListSize = ol.size();
                        System.out.println("Table size = " + dataListSize);
                        table.getColumns().get(0).setVisible(false);
                        table.getColumns().get(0).setVisible(true);
                    }
                });
            }
        });

        table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
        table.setItems(ol);
        borderPane.setCenter(table);
        BorderPane.setAlignment(table, Pos.CENTER);
        BorderPane.setMargin(table, new Insets(25));

        // Add columns
        TableColumn<TableData, String> c1 = new TableColumn<TableData, String>("FirstName");
        c1.setCellValueFactory(new PropertyValueFactory<TableData, String>("firstName"));
        c1.setCellFactory(new TextFieldCellFactory());

        TableColumn<TableData, String> c2 = new TableColumn<TableData, String>("LastName");
        c2.setCellValueFactory(new PropertyValueFactory<TableData, String>("lastName"));
        c2.setCellFactory(new TextFieldCellFactory());

        TableColumn<TableData, String> c3 = new TableColumn<TableData, String>("Phone");
        c3.setCellValueFactory(new PropertyValueFactory<TableData, String>("phone"));
        c3.setCellFactory(new TextFieldCellFactory());

        TableColumn<TableData, String> c4 = new TableColumn<TableData, String>("Email");
        c4.setCellValueFactory(new PropertyValueFactory<TableData, String>("email"));
        c4.setCellFactory(new TextFieldCellFactory());

        table.getColumns().addAll(c1, c2, c3, c4);

        scene.getStylesheets().add(TableViewEditingWithBinding.class.getResource("styles.css").toExternalForm());
        Stage.setScene(scene);
        Stage.show();
    }
}

次のコードを追加してみました

table.getColumns().get(0).setVisible(false);
table.getColumns().get(0).setVisible(true);
行が追加された後の addRow ボタンのハンドラーで、しかしそれは何の助けにもなりませんでした。

また、バッキングオブザーバブルリストをクリアし、値をリスト+各行が追加された後の新しい行にリセットしようとしました。それも問題を解決しませんでした。
どんな助けでも大歓迎です。

4

1 に答える 1

0

私も同じ問題を抱えていました。1 つの行を削除すると、他の行が空白になります。スクロールすると、空白行が変更されました。

私の解決策は、行を移動することでした

setContentDisplay(ContentDisplay.GRAPHIC_ONLY);

セルのコンストラクターに渡して、行を削除します

setContentDisplay(ContentDisplay.TEXT_ONLY);

完全に。

Cell.updateItem状態の API ドキュメント

empty- このセルがリストのデータを表すかどうか。空の場合、それはドメイン データを表しませんが、「空の」行をレンダリングするために使用されるセルです。

私の場合、これは JavaFX のバグのように見えます。これは、すべての行がドメイン データでサポートされているにもかかわらず、一部の行 (スクロール時に変化) が wi​​th を受け取るためupdateItem()ですempty=true

于 2013-06-02T08:00:12.023 に答える