java—通过单个属性更新javafx tableview并用行颜色反映该属性

pnwntuvh  于 2021-07-03  发布在  Java
关注(0)|答案(2)|浏览(324)

有人能解释一下为什么我的tableview没有自动更新吗?
最后我想得到的是,表会根据“change”属性的外部更新更改行的颜色。updateitem(person-item,boolean-empty)和.itemproperty().addlistener()都不对属性更改作出React。
我想到的是让person类成为一个属性,它对其字段(也是属性)的更改做出React,但是如果主类必须对几十个字段做出React呢?

public class TableViewWithProperties extends Application {

    private final TableView<Person> table = new TableView<>();
    private final ObservableList<Person> data = FXCollections.observableArrayList(
            new Person("Jacob", "Smith", true),
            new Person("Isabella", "Johnson", false),
            new Person("Ethan", "Williams", false)
    );

    private void setRowFactory() {
        table.setRowFactory(param -> {
            TableRow<Person> row = new TableRow<Person>() {
                @Override
                protected void updateItem(Person item, boolean empty) {
                    super.updateItem(item, empty);

                    if (item != null && item.checked.get())
                        setStyle("-fx-background-color: #cceeff; -fx-text-fill: #990000;");
                }
            };

            row.itemProperty().addListener((obs, oldValue, newValue) -> {
                if (newValue != null) {
                    if (newValue.getChecked())
                        row.styleProperty().setValue("-fx-background-color: blue ;");
                    else
                        row.styleProperty().setValue("");
                }
            });

            return row;
        });
    }

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

    @Override
    public void start(Stage stage) {
        stage.setTitle("Table Properties test");

        TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
        TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name");
        TableColumn<Person, Boolean> isCheckedCol = new TableColumn<>("Is Checked");

        firstNameCol.setCellValueFactory(v -> v.getValue().firstName);
        lastNameCol.setCellValueFactory(v -> v.getValue().lastName);
        isCheckedCol.setCellValueFactory(v -> v.getValue().checked);

        setRowFactory();

        table.setItems(data);
        table.getColumns().addAll(firstNameCol, lastNameCol, isCheckedCol);
        VBox vbox = new VBox();
        vbox.setPadding(new Insets(10, 10, 10, 10));
        vbox.getChildren().addAll(table);
        Scene scene = new Scene(vbox);
        stage.setScene(scene);
        stage.show();

        scheduleUpdate();
    }

    private void scheduleUpdate() {
        Thread t = new Thread(new Runnable() {
            public void run()
            {
                try {
                    Thread.sleep(5000);
                    table.getItems().get(1).checked.setValue(true);
                    Thread.sleep(5000);
                    table.getItems().get(0).checked.setValue(false);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }});
        t.start();
    }

    public class Person {

        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;
        private final SimpleBooleanProperty checked;

        private Person(String fName, String lName, Boolean flag) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.checked = new SimpleBooleanProperty(flag);

            this.checked.addListener(new ChangeListener<Boolean>() {
                @Override
                public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                    System.out.println("Test: " + lastName.get() + " property reacted to value change to: " + newValue);
                }
            });
        }

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

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

        public boolean getChecked() {
            return checked.get();
        }
    }
}
9o685dep

9o685dep1#

对超级的呼唤 super.updateItem(item, empty); 在你的 updateItem 方法打破一切。删除它。
没有这条线,这个方法就可以很好地工作,但第二个问题是 setStyle 打电话。此方法调用不会影响行。
在你的 updateItem 方法替换:

setStyle("-fx-background-color: #cceeff; -fx-text-fill: #990000;");

使用:

BackgroundFill fill = new BackgroundFill(Color.rgb( 255, 0, 0, 1 ),  
                                CornerRadii.EMPTY, Insets.EMPTY); 
setBackground( new Background( fill ) );

你会看到它会起作用的。更改颜色代码以满足您的需要。
但是,更改行的样式通常不是正确的方法。这就是为什么 setStyle 没有给出预期的结果。最好加一个 CellFactory 对每个 TableColumn 改变每个单元格的样式:

isCheckedCol.setCellFactory(new Callback<TableColumn, TableCell>() {
    public TableCell call(TableColumn param) {
        return new TableCell<TableData, String>() {

            @Override
            public void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);
                if (item != null && item.checked.get())
                        setStyle("-fx-background-color: #cceeff; -fx-text-fill: #990000;");
            }
        };
    }
});
7z5jn7bk

7z5jn7bk2#

我使用这个解决方案是因为它只需要在单个列上调用。

private void setCustomFactory(TableColumn<Person, Boolean> call) {
        call.setCellFactory(column -> {
            return new TableCell<Person, Boolean>() {
                @Override
                protected void updateItem(Boolean item, boolean empty) {
                    super.updateItem(item, empty);
                    setText(empty ? "" : getItem().toString());
                    TableRow<Person> currentRow = getTableRow();

                    if (!isEmpty()) {
                        if(item)
                            currentRow.setStyle("-fx-background-color: #cceeff;");
                        else
                            currentRow.setStyle("");
                    }
                }
            };
        });
    }

相关问题