Listview 理解cell工厂和回调
我正在尝试为ListView实现自定义cellFactory。 我的应用程序基于我从另一个线程获取的这个示例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
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(),但没有参数传递给该构造函数
列表视图
上设置工厂。工厂本质上是一个为列表视图
创建列表单元格
的函数。因此,调用(…)
方法只需返回一个ListCell
:在这种情况下,您将返回XCell
子类的一个实例
ListView
的工作方式(至少在概念上)如下:
最初,它使用单元工厂为每个可见单元创建ListCell
s,并布局这些单元。然后,它计算出每个单元格中要显示的值,并在每个单元格上调用updateItem(…)
方法,传入该项。如果列表中的项目数超出了所需的空间,它将用额外的单元格填充它们,并调用updateItem(null,true)
以指示这些单元格为空
随着要显示的项目的更改:ListView
将重新计算要显示的项目,并调用updateItem(…)
传递新项目,这可能是由于列表内容的更改,也可能是由于用户的滚动(或其他机制,如ListView
更改大小等)。这样,当用户滚动时,这些单元可以被重用,并且创建新单元实例的需要被最小化
因此,在实现Cell
s时,必须考虑到updateItem(…)
方法可能会被多次调用,而创建新的Cell
实例相对较少。因此,u