当前位置: 首页 > 知识库问答 >
问题:

了解cell工厂和回调

乐华晖
2023-03-14

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

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);
    }
}

因此,对于该列表的每一行,都将创建一个新的XCell对象,hBox将从中显示。然而,尽管有文档记录,我不理解以下事情是如何发生的:

>

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

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

    有人能给我解释一下吗?

  • 共有1个答案

    左丘智渊
    2023-03-14

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

    是的,没错。从单元格的文档中:

    因为到目前为止,单元格最常见的用例是向用户显示文本,因此此用例特别针对Cell中进行了优化。这是由从标签扩展的Cell完成的。这意味着Cell的子类只需要设置文本属性,而不是创建单独的Label并在Cell中设置它。但是,对于不仅仅需要纯文本的情况,可以将任何节点放置在Cell图形属性中。尽管有这个术语,图形可以是任何节点,并且将是完全交互式的。例如,ListCell可能配置为按钮作为其图形。按钮文本可以绑定到单元格项属性。这样,每当单元格中的项目发生变化时,按钮文本就会自动更新。

    您的下一个问题:

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

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

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

    最初,它使用单元格工厂为每个可见单元格创建ListCells,并将这些单元格排列出来。然后它找出要在每个单元格中显示的值,并在每个单元格上调用updateItem(...)方法,传入项目。如果空间超过列表中项目数所需的空间,它将用额外的单元格填充它们,并调用updateItem(null, true)来指示这些单元格为空。

    当要显示的项目发生变化时:通过列表内容的变化,或通过用户滚动(或通过其他机制,例如ListView更改大小等),ListView将重新计算要显示的项目,并调用updateItem(...)传入新项目。这样,当用户滚动时,可以重用单元格,并且最大限度地减少创建新单元格实例的需要。

    因此,当您实现Cells时,重要的是要尊重这样一个事实,即updateItem(...)方法可能会被多次调用,而新的Cell实例的创建相对较少。因此,updateItem(...)方法应该快速执行;任何更重量级的事情都应该在构造函数中完成一次。请注意,在您展示的XCell实现中,所有Nodes(HBoxLabelPaneButton)的创建和布局是在构建时完成的。updateItem(...)只需更新标签的文本即可完成这一最少的工作。

     类似资料:
    • 问题内容: 我第一次尝试AngularJS。我正在使用工厂从http-get请求中获取JSON数据,但是在完成ajax请求之前,该对象返回为空。 厂: 控制器: 这就是我想出的。当控制器设置$ scope.photos时,该值为空,就好像它在填充ajax响应之前返回photos数组。 问题答案: 您应该修改代码以返回承诺并使用控制器中的值,请参见伪修改后的代码 和控制器-

    • 问题内容: 我是一个长期的PHP(CodeIgniter和WordPress)开发人员,直到最近才想学习其他几种语言。我已经着手通过node.js学习Ruby(在Rails和Sinatra上),Python(在Flask框架下)和Javascript。 我决定使用每种语言创建一个我能想到的最基本的应用程序,即URL扩展器。除了node.js和Javascript,我已经设法用每种语言创建了一个工作

    • 问题内容: 编辑2016年1月: 由于这仍然引起注意。自问了这个之后,我已经完成了一些AngularJS项目,对于我最常使用的那些项目,建立了一个对象并最后返回了该对象。但是,我下面的说法仍然正确。 编辑: 我想我终于了解了两者之间的主要区别,并且我有一个代码示例来演示。我也认为这个问题与建议的重复问题有所不同。重复项说明该服务不可实例化,但是如果您按照我在下面的演示中进行设置,它实际上是可实例化

    • 本文向大家介绍简单工厂和抽象工厂有什么区别?相关面试题,主要包含被问及简单工厂和抽象工厂有什么区别?时的应答技巧和注意事项,需要的朋友参考一下 简单工厂:用来生产同一等级结构中的任意产品,对于增加新的产品,无能为力。 工厂方法:用来生产同一等级结构中的固定产品,支持增加任意产品。 抽象工厂:用来生产不同产品族的全部产品,对于增加新的产品,无能为力;支持增加产品族。

    • 我是新泉。在Bean标记中,我发现了factory-method和factory-method和factory-bean之间有什么区别? 我正在使用factory-method调用我的getInstance静态方法来创建singleton对象。 工厂豆是用来做什么的? 对于给定的答复,我所理解的是 Factory-method用于调用静态方法在同一个bean类中创建对象。 Factory-bean

    • 问题内容: 我是AngularJS的新手,因此遇到了这个问题。 我可以在所有注入了控制器的工厂中重新注入我的工厂单例对象吗? 例如: 在MedicalCenterController中,当应用程序启动时,我得到了带有医疗中心的单例对象: 但是稍后,我尝试在AccountProfileController中编辑医疗中心字段(名称,地址等)。 我期望的是具有更新字段的对象。如何返回我的单身人士的新实例