如何扩展 JavaFX 分页导航以显示其他控件?

How to extend JavaFX Pagination navigation to display additional controls?

我想使用分页来显示 table 页面。这原则上有效,但我想添加与默认分页导航位于同一行的其他控件:

我可以使用方法 setPageFactory() 自定义分页控件上方的页面,但我无法自定义导航控件本身。怎么做?如果我在默认导航的上方或下方添加额外的控件,我会浪费一些 space:

相关文章: JavaFX Pagination, adding << and >>> options

提交了 enhancement request

不支持自定义导航控件。在等待 the enhancement request 被修复的同时,我们可以应用如下所述的 hack(如果 QA 指南允许)。这是一个 hack,因为与导航控件相关的所有内容在 PaginationSkin 中都是私有包,而 PaginationSkin 本身还不是 public api.

基本思想是在核心导航控件中插入额外的节点,这显然意味着依赖于实现细节(不要,不要,不要:-)。我们在实例化时即时执行此操作,并且每当再次插入下一个按钮时 - 核心在分页的布局和状态更改期间经常清除其所有子项。这涉及:

  • 查找包含按钮的窗格,它的选择器是控制框
  • 保留对其最后一个子项的引用,即下一个按钮
  • 向窗格的子项添加侦听器以便能够插入自定义控件

自定义皮肤的代码示例,这里只是 first/last 的两个按钮:

public static class CustomPaginationSkin extends PaginationSkin {

    private HBox controlBox;
    private Button prev;
    private Button next;
    private Button first;
    private Button last;

    private void patchNavigation() {
        Pagination pagination = getSkinnable();
        Node control = pagination.lookup(".control-box");
        if (!(control instanceof HBox))
            return;
        controlBox = (HBox) control;
        prev = (Button) controlBox.getChildren().get(0);
        next = (Button) controlBox.getChildren().get(controlBox.getChildren().size() - 1);

        first = new Button("A");
        first.setOnAction(e -> {
            pagination.setCurrentPageIndex(0);
        });
        first.disableProperty().bind(
                pagination.currentPageIndexProperty().isEqualTo(0));

        last = new Button("Z");
        last.setOnAction(e -> {
            pagination.setCurrentPageIndex(pagination.getPageCount());
        });
        last.disableProperty().bind(
                pagination.currentPageIndexProperty().isEqualTo(
                        pagination.getPageCount() - 1));

        ListChangeListener childrenListener = c -> {
            while (c.next()) {
                // implementation detail: when nextButton is added, the setup is complete
                if (c.wasAdded() && !c.wasRemoved() // real addition
                        && c.getAddedSize() == 1 // single addition
                        && c.getAddedSubList().get(0) == next) { 
                    addCustomNodes();
                }
            }
        };
        controlBox.getChildren().addListener(childrenListener);
        addCustomNodes();
    }

    protected void addCustomNodes() {
        // guarding against duplicate child exception 
        // (some weird internals that I don't fully understand...)
        if (first.getParent() == controlBox) return;
        controlBox.getChildren().add(0, first);
        controlBox.getChildren().add(last);
    }

    /**
     * @param pagination
     */
    public CustomPaginationSkin(Pagination pagination) {
        super(pagination);
        patchNavigation();
    }

}