Listview 理解cell工厂和回调

Listview 理解cell工厂和回调,listview,callback,javafx,Listview,Callback,Javafx,我正在尝试为ListView实现自定义cellFactory。 我的应用程序基于我从另一个线程获取的这个示例 import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.event.EventHandler; import

我正在尝试为ListView实现自定义cellFactory。 我的应用程序基于我从另一个线程获取的这个示例

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;

public class SO extends Application {
    static class XCell extends ListCell<String> {
        HBox hbox = new HBox();
        Label label = new Label("(empty)");
        Pane pane = new Pane();
        Button button = new Button("(>)");
        String lastItem;

        public XCell() {
            super();
            hbox.getChildren().addAll(label, pane, button);
            HBox.setHgrow(pane, Priority.ALWAYS);
            button.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    System.out.println(lastItem + " : " + event);
                }
            });
        }

        @Override
        protected void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            setText(null);  // No text in label of super class
            if (empty) {
                lastItem = null;
                setGraphic(null);
            } else {
                lastItem = item;
                label.setText(item!=null ? item : "<null>");
                setGraphic(hbox);
            }
        }
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        StackPane pane = new StackPane();
        Scene scene = new Scene(pane, 300, 150);
        primaryStage.setScene(scene);
        ObservableList<String> list = FXCollections.observableArrayList(
                "Item 1", "Item 2", "Item 3", "Item 4");
        ListView<String> lv = new ListView<>(list);
        lv.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
            @Override
            public ListCell<String> call(ListView<String> param) {
                return new XCell();
            }
        });
        pane.getChildren().add(lv);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
导入javafx.application.application;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.event.ActionEvent;
导入javafx.event.EventHandler;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.scene.control.Label;
导入javafx.scene.control.ListCell;
导入javafx.scene.control.ListView;
导入javafx.scene.layout.HBox;
导入javafx.scene.layout.Pane;
导入javafx.scene.layout.Priority;
导入javafx.scene.layout.StackPane;
导入javafx.stage.stage;
导入javafx.util.Callback;
公共类因此扩展了应用程序{
静态类XCell扩展了ListCell{
HBox HBox=新的HBox();
标签标签=新标签(“(空)”);
窗格=新窗格();
按钮按钮=新按钮(“(>)”);
字符串最后一项;
公共XCell(){
超级();
hbox.getChildren().addAll(标签、窗格、按钮);
HBox.setHgrow(窗格,Priority.ALWAYS);
setOnAction(新的EventHandler(){
@凌驾
公共无效句柄(ActionEvent事件){
System.out.println(lastItem+“:”+事件);
}
});
}
@凌驾
受保护的void updateItem(字符串项,布尔值为空){
super.updateItem(项,空);
setText(null);//超类的标签中没有文本
if(空){
lastItem=null;
设置图形(空);
}否则{
lastItem=项目;
label.setText(项!=null?项:“”);
设置图形(hbox);
}
}
}
@凌驾
public void start(Stage primaryStage)引发异常{
StackPane=新的StackPane();
场景=新场景(窗格,300150);
初级阶段。场景(场景);
ObservableList=FXCollections.observableArrayList(
“第1项”、“第2项”、“第3项”、“第4项”);
ListView lv=新的ListView(列表);
lv.setCellFactory(新回调(){
@凌驾
公共ListCell调用(ListView参数){
返回新的XCell();
}
});
pane.getChildren().add(lv);
primaryStage.show();
}
公共静态void main(字符串[]args){
发射(args);
}
}
因此,对于该列表的每一行,将创建一个新的XCell对象,hBox将从中显示。 然而,尽管有文档记录,我并不理解以下事情是如何发生的:

  • 这是模糊的,但我可以猜hBox的出现是因为ListCell.setgraphics(继承自标记的类)

  • 在XCell.updateItem(字符串项,布尔空)中,参数是如何传递给该方法的? 调用ListView中包含的每个字符串,它返回一个新的XCell(),但没有参数传递给该构造函数

有人能给我解释一下吗

这是模糊的,但我可以猜hBox的出现是因为 ListCell.setgraphics(从标记的类继承)

是的,没错。从:

因为到目前为止,单元格最常见的用例是向 用户,这个用例是专门为单元内部优化的。这是 由标记的细胞延伸而成。这意味着 单元格只需设置文本属性,而无需创建单独的 在单元格中标记并设置。但是,对于以下情况: 需要的不仅仅是纯文本,还可以 将任意节点放置在“单元图形”属性中。尽管有这个词,一个 图形可以是任何节点,并且将是完全交互的。例如,一个 ListCell可能配置了一个按钮作为其图形。按钮 然后可以将文本绑定到cells项属性。这样,, 每当单元格中的项目发生更改时,按钮文本都会显示 自动更新

你的下一个问题:

在XCell.updateItem(字符串项,布尔空)中 传递给该方法的参数?对每个字符串进行调用 包含在ListView中,它返回一个新的XCell(),但没有 参数传递给该构造函数

您正在
列表视图
上设置工厂。工厂本质上是一个为
列表视图
创建
列表单元格
的函数。因此,
调用(…)
方法只需返回一个
ListCell
:在这种情况下,您将返回
XCell
子类的一个实例

ListView
的工作方式(至少在概念上)如下:

最初,它使用单元工厂为每个可见单元创建
ListCell
s,并布局这些单元。然后,它计算出每个单元格中要显示的值,并在每个单元格上调用
updateItem(…)
方法,传入该项。如果列表中的项目数超出了所需的空间,它将用额外的单元格填充它们,并调用
updateItem(null,true)
以指示这些单元格为空

随着要显示的项目的更改:
ListView
将重新计算要显示的项目,并调用
updateItem(…)
传递新项目,这可能是由于列表内容的更改,也可能是由于用户的滚动(或其他机制,如
ListView
更改大小等)。这样,当用户滚动时,这些单元可以被重用,并且创建新单元实例的需要被最小化

因此,在实现
Cell
s时,必须考虑到
updateItem(…)
方法可能会被多次调用,而创建新的
Cell
实例相对较少。因此,
u