【问题标题】:JavaFx 2.1, 2.2 TableView update issueJavaFx 2.1、2.2 TableView 更新问题
【发布时间】:2012-07-01 14:40:22
【问题描述】:

我的应用程序使用 JPA 将数据读取到 TableView 中,然后修改并显示它们。该表刷新了 JavaFx 2.0.3 下的修改记录。在 JavaFx 2.1、2.2 下,表格不再刷新更新。我发现其他人也有类似的问题。我的计划是继续使用 2.0.3,直到有人解决了 2.1 和 2.2 下的问题。现在我知道这不是一个错误,也不会被修复。嗯,我不知道如何处理这个。以下是从示例演示修改的代码以显示问题。如果我从表中添加新记录或删除旧记录,表刷新正常。如果我修改了一条记录,在执行添加、删除或排序操作之前,表格不会刷新更改。如果我删除修改后的记录并再次添加,表格会刷新。但是修改后的记录放在表格的按钮上。好吧,如果我删除修改过的记录,添加相同的记录,然后将记录移动到原始位置,表格将不再刷新。下面是一个完整的代码,请对此有所了解。

    import javafx.application.Application;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.geometry.HPos;
    import javafx.geometry.Insets;
    import javafx.geometry.Pos;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.scene.control.cell.PropertyValueFactory;
    import javafx.scene.layout.GridPane;
    import javafx.scene.layout.HBox;
    import javafx.scene.layout.VBox;
    import javafx.scene.text.Font;
    import javafx.stage.Modality;
    import javafx.stage.Stage;
    import javafx.stage.StageStyle;

    public class Main extends Application {

        private TextField firtNameField = new TextField();
        private TextField lastNameField = new TextField();
        private TextField emailField = new TextField();
        private Stage editView;
        private Person fPerson;

        public static class Person {

            private final SimpleStringProperty firstName;
            private final SimpleStringProperty lastName;
            private final SimpleStringProperty email;

            private Person(String fName, String lName, String email) {
                this.firstName = new SimpleStringProperty(fName);
                this.lastName = new SimpleStringProperty(lName);
                this.email = new SimpleStringProperty(email);
            }

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

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

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

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

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

            public void setEmail(String fName) {
                email.set(fName);
            }
        }
        private TableView<Person> table = new TableView<Person>();
        private final ObservableList<Person> data =
                FXCollections.observableArrayList(
                new Person("Jacob", "Smith", "jacob.smith@example.com"),
                new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
                new Person("Ethan", "Williams", "ethan.williams@example.com"),
                new Person("Emma", "Jones", "emma.jones@example.com"),
                new Person("Michael", "Brown", "michael.brown@example.com"));

        public static void main(String[] args) {
            launch(args);
        }

        @Override
        public void start(Stage stage) {
            Scene scene = new Scene(new Group());
            stage.setTitle("Table View Sample");
            stage.setWidth(535);
            stage.setHeight(535);
            editView = new Stage();

            final Label label = new Label("Address Book");
            label.setFont(new Font("Arial", 20));

            TableColumn firstNameCol = new TableColumn("First Name");
            firstNameCol.setCellValueFactory(
                    new PropertyValueFactory<Person, String>("firstName"));
            firstNameCol.setMinWidth(150);

            TableColumn lastNameCol = new TableColumn("Last Name");
            lastNameCol.setCellValueFactory(
                    new PropertyValueFactory<Person, String>("lastName"));
            lastNameCol.setMinWidth(150);
            TableColumn emailCol = new TableColumn("Email");
            emailCol.setMinWidth(200);
            emailCol.setCellValueFactory(
                    new PropertyValueFactory<Person, String>("email"));

            table.setItems(data);
            table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
    //--- create a edit button and a editPane to edit person   
            Button addButton = new Button("Add");
            addButton.setOnAction(new EventHandler<ActionEvent>() {

                @Override
                public void handle(ActionEvent event) {
                    fPerson = null;
                    firtNameField.setText("");
                    lastNameField.setText("");
                    emailField.setText("");
                    editView.show();
                }
            });
            Button editButton = new Button("Edit");
            editButton.setOnAction(new EventHandler<ActionEvent>() {

                @Override
                public void handle(ActionEvent event) {
                    if (table.getSelectionModel().getSelectedItem() != null) {
                        fPerson = table.getSelectionModel().getSelectedItem();
                        firtNameField.setText(fPerson.getFirstName());
                        lastNameField.setText(fPerson.getLastName());
                        emailField.setText(fPerson.getEmail());
                        editView.show();
                    }
                }
            });
            Button deleteButton = new Button("Delete");
            deleteButton.setOnAction(new EventHandler<ActionEvent>() {

                @Override
                public void handle(ActionEvent event) {
                    if (table.getSelectionModel().getSelectedItem() != null) {
                        data.remove(table.getSelectionModel().getSelectedItem());
                    }
                }
            });
            HBox addEditDeleteButtonBox = new HBox();
            addEditDeleteButtonBox.getChildren().addAll(addButton, editButton, deleteButton);
            addEditDeleteButtonBox.setAlignment(Pos.CENTER_RIGHT);
            addEditDeleteButtonBox.setSpacing(3);

            GridPane editPane = new GridPane();
            editPane.getStyleClass().add("editView");
            editPane.setPadding(new Insets(3));
            editPane.setHgap(5);
            editPane.setVgap(5);
            Label personLbl = new Label("Person:");
            editPane.add(personLbl, 0, 1);
            GridPane.setHalignment(personLbl, HPos.LEFT);

            firtNameField.setPrefWidth(250);
            lastNameField.setPrefWidth(250);
            emailField.setPrefWidth(250);
            Label firstNameLabel = new Label("First Name:");
            Label lastNameLabel = new Label("Last Name:");
            Label emailLabel = new Label("Email:");

            editPane.add(firstNameLabel, 0, 3);
            editPane.add(firtNameField, 1, 3);
            editPane.add(lastNameLabel, 0, 4);
            editPane.add(lastNameField, 1, 4);
            editPane.add(emailLabel, 0, 5);
            editPane.add(emailField, 1, 5);
            GridPane.setHalignment(firstNameLabel, HPos.RIGHT);
            GridPane.setHalignment(lastNameLabel, HPos.RIGHT);
            GridPane.setHalignment(emailLabel, HPos.RIGHT);

            Button saveButton = new Button("Save");
            saveButton.setOnAction(new EventHandler<ActionEvent>() {

                @Override
                public void handle(ActionEvent event) {
                    if (fPerson == null) {
                        fPerson = new Person(
                                firtNameField.getText(),
                                lastNameField.getText(),
                                emailField.getText());
                        data.add(fPerson);
                    } else {
                        int k = -1;
                        if (data.size() > 0) {
                            for (int i = 0; i < data.size(); i++) {
                                if (data.get(i) == fPerson) {
                                    k = i;
                                }
                            }
                        }
                        fPerson.setFirstName(firtNameField.getText());
                        fPerson.setLastName(lastNameField.getText());
                        fPerson.setEmail(emailField.getText());
                        data.set(k, fPerson);
                        table.setItems(data);

    //  The following will work, but edited person has to be added to the button
    //
    //                    data.remove(fPerson);
    //                    data.add(fPerson);

    // add and remove refresh the table, but now move edited person to original spot, 
    // it failed again with the following code
    //                    while (data.indexOf(fPerson) != k) {
    //                        int i = data.indexOf(fPerson);
    //                        Collections.swap(data, i, i - 1);
    //                    }
                    }
                    editView.close();
                }
            });
            Button cancelButton = new Button("Cancel");
            cancelButton.setOnAction(new EventHandler<ActionEvent>() {

                @Override
                public void handle(ActionEvent event) {
                    editView.close();
                }
            });

            HBox saveCancelButtonBox = new HBox();
            saveCancelButtonBox.getChildren().addAll(saveButton, cancelButton);
            saveCancelButtonBox.setAlignment(Pos.CENTER_RIGHT);
            saveCancelButtonBox.setSpacing(3);

            VBox editBox = new VBox();
            editBox.getChildren().addAll(editPane, saveCancelButtonBox);

            Scene editScene = new Scene(editBox);
            editView.setTitle("Person");
            editView.initStyle(StageStyle.UTILITY);
            editView.initModality(Modality.APPLICATION_MODAL);
            editView.setScene(editScene);
            editView.close();

            final VBox vbox = new VBox();
            vbox.setSpacing(5);
            vbox.getChildren().addAll(label, table, addEditDeleteButtonBox);
            vbox.setPadding(new Insets(10, 0, 0, 10));

            ((Group) scene.getRoot()).getChildren().addAll(vbox);

            stage.setScene(scene);
            stage.show();
        }
    }

【问题讨论】:

    标签: javafx-2


    【解决方案1】:

    the answer to Updating rows in Tableview。添加这些吸气剂,它就可以工作了。
    此外,由于data 是一个ObservableList,它被设置为tableView 的项目,因此对此data 列表的任何更改也将反映到table.getItems()。即无需再次table.setItems(data)

    【讨论】:

    • 添加吸气剂确实使演示工作。但这对我的应用程序来说将是一个麻烦。我使用 Netbeans 从数据库中生成大约 100 个实体类。每个类都有很多领域。这将有很多吸气剂要添加。另一方面,是什么让 JavaFX 2.0.3 有效?
    • JPA POJO 实现了可序列化。 SimpleStringProperty 不是可序列化的类型。我什至无法将 SimpleStringProperty 添加到我的 POJO 中。
    • 有一个Jira issue关于这个问题。你可能想投票给它。
    【解决方案2】:

    我在JavaFX 2.1 TableView refresh items 中找到了触发 TableView 刷新的简单解决方法。它为我解决了这个问题。

    将此添加到您的代码中:

    tableView.getColumns().get(0).setVisible(false);
    tableView.getColumns().get(0).setVisible(true);
    

    【讨论】:

      【解决方案3】:

      查看 TableView.java 代码,有一个只执行的私有 refresh()

      getProperties().put(TableViewSkinBase.REFRESH, Boolean.TRUE); 
      

      最后,下面的代码对我有用(Java8)。 (注意,常量的名字不是 REFRESH 而是 RECREATE)

      tableView.getProperties().put(TableViewSkinBase.RECREATE, Boolean.TRUE);
      

      (读取 javafx 的代码,这将强制重新创建单元格)

      【讨论】:

        【解决方案4】:

        JavaFX 控件的基于通知的更新通常要求支持您的 GUI 的数据模型对象的属性满足 JavaFX Bean 的最低定义。

        以下示例说明了 JavaFX 属性满足这些要求所需的最少代码:

        public class Client extends DB {
        
            private IntegerProperty id =         new SimpleIntegerProperty();
            private StringProperty  lastName =   new SimpleStringProperty();
            private StringProperty  firstName =  new SimpleStringProperty();
        
        
            public final int getID() {return this.id.get(); }
            void setID(int id) { this.id.set(id); }
            public final IntegerProperty idProperty() { return this.id; }
        
            public final String getLastName() { return this.lastName.get(); }
            public final void setLastName(String ln) { this.lastName.set(ln); }
            public final StringProperty lastNameProperty() { return this.lastName; }
        
            public final String getFirstName() { return this.firstName.get(); }
            public final void setFirstName(String fn) { this.firstName.set(fn); }
            public final StringProperty firstNameProperty() { return this.firstName; }
            :
            :
        }    
        

        浏览您的代码,您的属性似乎不满足 JavFX Bean 的要求。因此,不会发生基于通知的自动更新。

        【讨论】:

          【解决方案5】:

          我有同样的问题,并且无法将SimpleStringProperty 添加到 JPA 使用的 POJO 中,这有点问题。但在我看来,这应该是可以解决的问题,因为我注意到以下行为:

          1. 在我的应用程序中,单击表格中的一行会在屏幕上填充一些文本字段,然后用户可以对其进行编辑。
          2. 此时用户可以保存数据,或使用相同或更改的数据创建新项目。如果用户创建了一个新项目,然后将其插入到 tableview 表示的 observable 列表中,则更改会立即反映在 tableview 的内容中。但是,如果用户只是保存更改,则新数据不会反映在表中。要将新数据放入列表中,我只是在做

            trialList.set(currentIndex, tempTrial);
            
          3. 我认为这是一个可修复的问题:如果我将受影响的行滚动到表格的视图之外,然后将其向后滚动,现在会显示“新”值。

          希望这可以解决。抱歉,这不是一个答案,可以这么说,但可能会为修复提供一些见解。

          【讨论】:

          • 来自另一个 JIRA 的人发布了一个解决方案。要更新,请执行:tableview.getColumns().get(0).setVisible(false) 和下一个 setVisible(true)。这很好用。
          【解决方案6】:

          这对我有用

          @FXML 
          private void refreshTableView()
          {
            firstNameCol.setVisible(false);
            lastNameCol.setVisible(false);
            emailCol.setVisible(false); 
            firstNameCol.setVisible(true);
            lastNameCol.setVisible(true);
            emailCol.setVisible(true);
          } 
          

          【讨论】:

            【解决方案7】:

            我遇到了同样的问题,经过一番搜索,这是我的解决方法。我发现如果列被删除然后重新添加,表格就会更新。

            public static <T,U> void refreshTableView(final TableView<T> tableView, final List<TableColumn<T,U>> columns, final List<T> rows) {
                if (tableView == null) {
                    throw new NullPointerException();
                }
                if (columns == null) {
                    throw new NullPointerException();
                }
                if (rows == null) {
                    throw new NullPointerException();
                }
            
                tableView.getColumns().clear();
                tableView.getColumns().addAll(columns);
            
                ObservableList<T> list = FXCollections.observableArrayList(rows);
                tableView.setItems(list);
            }
            


            用法示例:

            refreshTableView(myTableView, Arrays.asList(col1, col2, col3), rows);
            

            【讨论】:

              猜你喜欢
              • 2020-04-22
              • 2012-12-02
              • 1970-01-01
              • 2018-09-24
              • 2014-10-21
              • 2021-09-07
              • 1970-01-01
              • 2017-07-22
              • 1970-01-01
              相关资源
              最近更新 更多