java 删除项目后,使用自定义单元工厂的 ListView 不会更新

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28384803/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 13:30:23  来源:igfitidea点击:

ListView using custom cell factory doesn't update after items deleted

javalistviewjavafx

提问by Wermerb

I'm learning JavaFX and i wanted to create a cell factory which is working properly until i want to delete a row from my ListView:

我正在学习 JavaFX,我想创建一个正常工作的细胞工厂,直到我想从我的ListView

plateList.setCellFactory(new Callback<ListView<Car>, ListCell<Car>>() {

    @Override
    public ListCell<Car> call(ListView<Car> param) {
        ListCell<Car> cell = new ListCell<Car>() {

            @Override
            protected void updateItem(Car item, boolean empty) {
                super.updateItem(item, empty);
                if (item != null) {
                    setText(item.getPlate());
                }
            }
        };
        return cell;
    }
});

I'm populating the ListViewwith some sample data:

我正在填充ListView一些示例数据:

ObservableList<Car> sample = FXCollections.observableArrayList();
sample.add(new Car("123-abc", "opel", "corsa", 5.5));
sample.add(new Car("123-cba", "vw", "passat", 7.5));
plateList.setItems(sample);

Now i will see what i expect the ListViewwill be the following:

现在我将看到我期望ListView的内容如下:

  • 123-abc
  • 123-cba
  • 123-abc
  • 123-cba

How ever if delete a row ex: the first row (123-abc), the ListViewwill look like this:

如果删除一行 ex: 第一行 (123-abc),ListView它将如下所示:

  • 123-cba
  • 123-cba
  • 123-cba
  • 123-cba

This is the delete part:

这是删除部分:

@FXML
private void deleteBtnAction() {
    plateList.getItems().remove(plateList.getSelectionModel().getSelectedItem());
    ObservableList<Car> t = plateList.getItems();
    plateList.setItems(t);
}

If i remove the cell factory the program works as intended. Any help is greatly appreciated.

如果我移除细胞工厂,程序会按预期工作。任何帮助是极大的赞赏。

回答by Adam

Try changing to the following, This is required as JavaFX reuses the list cells, so the updateItem() needs to blank unused ones too when passed null

尝试更改为以下内容,这是 JavaFX 重用列表单元格所必需的,因此 updateItem() 在传递 null 时也需要将未使用的单元格清空

super.updateItem(item, empty);
if (item != null) {
   setText(item.getPlate());
} else {
   setText("");   // <== clear the now empty cell.
}

Full SSCCE

完整的SSCCE

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;

public class JavaFxListView extends Application {

    private static class Car {
        private String plate;

        public Car(String plate, String string2, String string3, double d) {
            this.plate = plate;
        }

        public String getPlate() {
            return plate;
        }

    }

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

    @Override
    public void start(Stage arg0) throws Exception {
        ListView<Car> plateList = new ListView<Car>();
        plateList.setCellFactory(new Callback<ListView<Car>, ListCell<Car>>() {

            @Override
            public ListCell<Car> call(ListView<Car> param) {
                ListCell<Car> cell = new ListCell<Car>() {

                    @Override
                    protected void updateItem(Car item, boolean empty) {
                        super.updateItem(item, empty);
                        if (item != null) {
                            setText(item.getPlate());
                        } else {
                            setText("");
                        }
                    }
                };
                return cell;
            }
        });
        Button delete = new Button("Delete");
        ObservableList<Car> sample = FXCollections.observableArrayList();
        sample.add(new Car("123-abc", "opel", "corsa", 5.5));
        sample.add(new Car("123-cba", "vw", "passat", 7.5));

        delete.setOnAction((e) -> {
            plateList.getItems().remove(plateList.getSelectionModel().getSelectedItem());
            ObservableList<Car> t = plateList.getItems();
            plateList.setItems(t);
        });

        plateList.setItems(sample);
        arg0.setScene(new Scene(new VBox(plateList, delete)));
        arg0.show();
    }
}

回答by Zavael

According to the Java doc of Cell updateItemmethod, there is slightly different recomended usage than the accepted one:

根据Cell updateItem方法的 Java 文档,推荐的用法与接受的用法略有不同:

protected void updateItem(T item, boolean empty) {
    super.updateItem(item, empty);

    if (empty || item == null) {
        setText(null);
        setGraphic(null);
    } else {
        setText(item.toString());
    }
}

The difference is in the usage of parameter empty. But the sollution from @Adam should work correctly in major cases too.

不同之处在于参数的用法empty。但是@Adam 的解决方案在主要情况下也应该正常工作。