如何扩展 JavaFX 分页导航以显示其他控件?
How to extend JavaFX Pagination navigation to display additional controls?
我想使用分页来显示 table 页面。这原则上有效,但我想添加与默认分页导航位于同一行的其他控件:
- 转到第一页的按钮(“<<”)
- 用于跳转到指定页面索引的文本字段
- 转到最后一页的按钮(“>>”)
- 每页条目数的文本字段
- 用于跳转到包含具有给定 ID 的行条目的页面的搜索文本字段。
我可以使用方法 setPageFactory() 自定义分页控件上方的页面,但我无法自定义导航控件本身。怎么做?如果我在默认导航的上方或下方添加额外的控件,我会浪费一些 space:
相关文章:
JavaFX Pagination, adding << and >>> options
不支持自定义导航控件。在等待 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();
}
}
我想使用分页来显示 table 页面。这原则上有效,但我想添加与默认分页导航位于同一行的其他控件:
- 转到第一页的按钮(“<<”)
- 用于跳转到指定页面索引的文本字段
- 转到最后一页的按钮(“>>”)
- 每页条目数的文本字段
- 用于跳转到包含具有给定 ID 的行条目的页面的搜索文本字段。
我可以使用方法 setPageFactory() 自定义分页控件上方的页面,但我无法自定义导航控件本身。怎么做?如果我在默认导航的上方或下方添加额外的控件,我会浪费一些 space:
相关文章: JavaFX Pagination, adding << and >>> options
不支持自定义导航控件。在等待 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();
}
}