绑定到 ScrollPane ScrollBar 时奇怪的 ScrollBar 行为
Weird ScrollBar behavior when bound to ScrollPane ScrollBar
我构建了一个为 JavaFX 提供 Twitter Bootstrap navbar-like 行为的控件。它基本上由一个 StackPane 和一个背面的 ScrollPane 组成,一个 BorderPane 和顶部的 Bottom 栏,最后一个 BorderPane 和一个 ScrollBar 在最顶层的右边。
这应该支持以下场景:
- 顶部和底部的固定元素在滚动时不会移动(导航栏)
- 有一个位于内容顶部的滚动条,这与 ScrollPanes 将内容推到左侧的默认行为不同,以便为 built-in 滚动条
因此 StackPane 布局。
布局部分工作正常,符合我的要求。不过,我的 ScrollBar 表现得很奇怪。当内容可滚动时,本机滚动条(由 ScrollPane 管理的滚动条)如下所示:
红线表示拇指可能拥有的最大尺寸的估计值。因此对于可滚动的内容,ScrollBar 不是越高越好,这是正确的。
现在我的实现对可滚动内容的行为有所不同。我可以观察到两种行为:
ScrollBar 拇指很小,尽管本机拇指的大小正确。或者:
尽管内容是可滚动的,但缩略图具有最大尺寸。
虽然滚动有效,但这两个示例在视觉效果方面显然是错误的。
我绑定两个 ScrollBars 属性的代码如下所示:
vScrollBar.valueProperty().bindBidirectional(scrollPane.vvalueProperty());
vScrollBar.maxProperty().bind(scrollPane.vmaxProperty());
vScrollBar.minProperty().bind(scrollPane.vminProperty());
nodeListChangeListener = c -> {
ScrollBar hiddenScrollBar = getScrollBarFromScrollPane(scrollPane, Orientation.VERTICAL);
if (hiddenScrollBar != null) {
vScrollBar.visibleAmountProperty().bind(hiddenScrollBar.visibleAmountProperty());
vScrollBar.blockIncrementProperty().bind(hiddenScrollBar.blockIncrementProperty());
vScrollBar.unitIncrementProperty().bind(hiddenScrollBar.unitIncrementProperty());
scrollPane.getChildrenUnmodifiable().removeListener(nodeListChangeListener);
}
};
scrollPane.getChildrenUnmodifiable().addListener(nodeListChangeListener);
另一件值得一提的事情是,在我使用此控件的几乎所有其他地方,它的行为都是正确的。只有少数几个区域会发生这种情况,但我不明白它怎么可能。
所以最后:我在这里错过了什么属性?考虑到我将 ScrollPane ScrollBar 中的所有这些属性绑定到我的自定义覆盖 ScrollBar (vScrollBar
),两个 ScrollBar 的行为不应该相同吗?
(我假设 getScrollBarFromScrollPane(scrollPane, Orientation.VERTICAL);
调用 (ScrollBar)scrollPane.queryAccessibleAttribute(AccessibleAttribute.VERTICAL_SCROLLBAR);
)
我不知道您是如何创建组件的,但很可能 hiddenScrollBar
只是 null
并且可见的 ScrollBar 永远不会绑定到 ScrollPane 的 ScrollBar。
发生这种情况是因为 nodeListChangeListener
在创建 ScrollPaneSkin
期间收到通知,但在设置 属性 skin
之前,因此无法访问滚动条。
要正确绑定滚动条,您可以将侦听器添加到 skinProperty
:
scrollPane.skinProperty().addListener(c -> {
ScrollBar hiddenScrollBar = (ScrollBar)scrollPane.queryAccessibleAttribute(AccessibleAttribute.VERTICAL_SCROLLBAR);
if (hiddenScrollBar != null) {
bar.visibleAmountProperty().bind(hiddenScrollBar.visibleAmountProperty());
bar.blockIncrementProperty().bind(hiddenScrollBar.blockIncrementProperty());
bar.unitIncrementProperty().bind(hiddenScrollBar.unitIncrementProperty());
}
});
我构建了一个为 JavaFX 提供 Twitter Bootstrap navbar-like 行为的控件。它基本上由一个 StackPane 和一个背面的 ScrollPane 组成,一个 BorderPane 和顶部的 Bottom 栏,最后一个 BorderPane 和一个 ScrollBar 在最顶层的右边。 这应该支持以下场景:
- 顶部和底部的固定元素在滚动时不会移动(导航栏)
- 有一个位于内容顶部的滚动条,这与 ScrollPanes 将内容推到左侧的默认行为不同,以便为 built-in 滚动条
因此 StackPane 布局。
布局部分工作正常,符合我的要求。不过,我的 ScrollBar 表现得很奇怪。当内容可滚动时,本机滚动条(由 ScrollPane 管理的滚动条)如下所示:
红线表示拇指可能拥有的最大尺寸的估计值。因此对于可滚动的内容,ScrollBar 不是越高越好,这是正确的。
现在我的实现对可滚动内容的行为有所不同。我可以观察到两种行为:
ScrollBar 拇指很小,尽管本机拇指的大小正确。或者:
尽管内容是可滚动的,但缩略图具有最大尺寸。 虽然滚动有效,但这两个示例在视觉效果方面显然是错误的。 我绑定两个 ScrollBars 属性的代码如下所示:
vScrollBar.valueProperty().bindBidirectional(scrollPane.vvalueProperty());
vScrollBar.maxProperty().bind(scrollPane.vmaxProperty());
vScrollBar.minProperty().bind(scrollPane.vminProperty());
nodeListChangeListener = c -> {
ScrollBar hiddenScrollBar = getScrollBarFromScrollPane(scrollPane, Orientation.VERTICAL);
if (hiddenScrollBar != null) {
vScrollBar.visibleAmountProperty().bind(hiddenScrollBar.visibleAmountProperty());
vScrollBar.blockIncrementProperty().bind(hiddenScrollBar.blockIncrementProperty());
vScrollBar.unitIncrementProperty().bind(hiddenScrollBar.unitIncrementProperty());
scrollPane.getChildrenUnmodifiable().removeListener(nodeListChangeListener);
}
};
scrollPane.getChildrenUnmodifiable().addListener(nodeListChangeListener);
另一件值得一提的事情是,在我使用此控件的几乎所有其他地方,它的行为都是正确的。只有少数几个区域会发生这种情况,但我不明白它怎么可能。
所以最后:我在这里错过了什么属性?考虑到我将 ScrollPane ScrollBar 中的所有这些属性绑定到我的自定义覆盖 ScrollBar (vScrollBar
),两个 ScrollBar 的行为不应该相同吗?
(我假设 getScrollBarFromScrollPane(scrollPane, Orientation.VERTICAL);
调用 (ScrollBar)scrollPane.queryAccessibleAttribute(AccessibleAttribute.VERTICAL_SCROLLBAR);
)
我不知道您是如何创建组件的,但很可能 hiddenScrollBar
只是 null
并且可见的 ScrollBar 永远不会绑定到 ScrollPane 的 ScrollBar。
发生这种情况是因为 nodeListChangeListener
在创建 ScrollPaneSkin
期间收到通知,但在设置 属性 skin
之前,因此无法访问滚动条。
要正确绑定滚动条,您可以将侦听器添加到 skinProperty
:
scrollPane.skinProperty().addListener(c -> {
ScrollBar hiddenScrollBar = (ScrollBar)scrollPane.queryAccessibleAttribute(AccessibleAttribute.VERTICAL_SCROLLBAR);
if (hiddenScrollBar != null) {
bar.visibleAmountProperty().bind(hiddenScrollBar.visibleAmountProperty());
bar.blockIncrementProperty().bind(hiddenScrollBar.blockIncrementProperty());
bar.unitIncrementProperty().bind(hiddenScrollBar.unitIncrementProperty());
}
});