【问题标题】:JavaFX ListCell updateItem executes twice?JavaFX ListCell updateItem 执行两次?
【发布时间】:2019-11-22 22:58:41
【问题描述】:

我正在尝试在 ListView 中创建自定义单元格,但每次添加新项目时,updateItem(TextFlow item, Boolean empty) 都会执行两次:一次它收到 nulltrue,第二次不是(!nullfalse

如果我实现 setCellFactory 方法,那么我可以毫无问题地将项目添加到表中。

ListView without custom cellFactory

但是,当我实现它时,它只是创建了 10 个空单元格(内容在哪里?)。

ListView with custom cellFactory

public class Controller implements Initializable {

@FXML
private ListView <TextFlow> console;

private ObservableList<TextFlow> data = FXCollections.observableArrayList();

public void initialize(URL location, ResourceBundle resources) {

    console.setCellFactory(new Callback<ListView<TextFlow>, ListCell<TextFlow>>() {

        @Override
        public ListCell<TextFlow> call(ListView<TextFlow> param) {
            return new ListCell<TextFlow>() {
                @Override
                protected void updateItem(TextFlow item, boolean empty) {
                    super.updateItem(item, empty);

                    if (item != null) {
                        setItem(item);
                        setStyle("-fx-control-inner-background: blue;");
                    } else {
                        System.out.println("Item is null.");
                    }

                }
            };
        }

    });


    for (int i = 0 ; i < 10; i++) {
        Text txt = getStyledText("This is item number " + i + ".");
        TextFlow textFlow = new TextFlow();
        textFlow.getChildren().add(txt);
        data.add(textFlow);
    }

    console.setItems(data);

}

private Text getStyledText (String inputText) {
    Text text = new Text(inputText);
    text.setFont(new Font("Courier New",12));
    text.setFill(Paint.valueOf("#000000"));
    return text;
}
}

【问题讨论】:

    标签: java listview javafx


    【解决方案1】:

    updateItem 可以调用任意次数,可以传递不同的项目,并且单元格可以从空变为非空,反之亦然。 ListView 创建与您在屏幕上看到的一样多的单元格,并用项目填充它们。例如。滚动或修改 items 列表或调整 ListView 的大小可能会导致更新。

    因此,任何单元格都需要能够处理传递给updateItem 方法的任意项目序列(或null+empty)。

    此外,您应该避免自己调用setItem,因为super.updateItem 已经这样做了。如果要在单元格中显示项目,请改用setGraphic

    @Override
    public ListCell<TextFlow> call(ListView<TextFlow> param) {
        return new ListCell<TextFlow>() {
            @Override
            protected void updateItem(TextFlow item, boolean empty) {
                super.updateItem(item, empty);
    
                if (item != null) {
                    setStyle("-fx-control-inner-background: blue;");
                    setGraphic(item);
                } else {
                    setStyle(null);
                    setGraphic(null);
                    System.out.println("Item is null.");
                }
    
            }
        };
    }
    

    【讨论】:

    • 我认为传递Nodes 是个坏主意?
    • @Sedrick 是的,但我在回答中只关注一个问题。
    • @fabian 为什么传递Node 是个坏主意?
    • @Raccoon a) 您只能将节点添加到场景中一次。如果你想显示例如ListView 旁边的选定节点,你会遇到问题。此外,很难以这种方式获得有关给定项目的数据的任何信息。 b)Nodes 通常是大对象,虚拟化视图的重点是将使用的节点数量保持在少量(可见节点)。如果将您要创建 Nodes 的数据添加到项目列表中,并重用用作不同项目的单元格的节点,您应该更喜欢将所有节点同时保存在内存中。
    • @fabian 这很有道理!谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-15
    • 2016-06-29
    • 2016-12-15
    • 1970-01-01
    • 1970-01-01
    • 2017-04-18
    相关资源
    最近更新 更多