JavaFX ScrollPane的水平滚动条隐藏内容
JavaFX ScrollPane's horizontal scroll bar hides content
我将一些内容包装到 ScrollPane 中,因为如果内容不适合屏幕,我需要一个水平滚动条。
只要不需要滚动条就可以了:
然而,当显示滚动条时,它(垂直)隐藏了部分内容:
如何防止这种行为?内容应始终完整显示。我尝试使用 fitToHeight="true"
,但这没有用。
下面是一些示例 FXML(添加了多层 HBox 和 VBox 以模仿我的真实应用程序的结构):
<BorderPane>
<top>
<ScrollPane vbarPolicy="NEVER" fitToHeight="true">
<HBox>
<VBox>
<TitledPane text="Title">
<HBox spacing="100.0">
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
</HBox>
</TitledPane>
</VBox>
</HBox>
</ScrollPane>
</top>
<center>
</center>
<bottom>
</bottom>
</BorderPane>
您可以通过将 vbox 的 minHeight 设置为可以完全显示文本的大小来解决这个问题,或者您可以添加填充
例如(填充)
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.ColorPicker?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Text?>
<?import javafx.geometry.Insets?>
<BorderPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<top>
<ScrollPane vbarPolicy="NEVER" fitToHeight="true">
<HBox>
<VBox spacing="100.0">
<TitledPane text="Title">
<HBox>
<children>
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
</children>
</HBox>
</TitledPane>
<padding>
<Insets bottom="5.0" top="5.0" />
</padding>
</VBox>
</HBox>
</ScrollPane>
</top>
<center>
</center>
<bottom>
</bottom>
</BorderPane>
例如。 (最小高度)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.*?>
<BorderPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<top>
<ScrollPane vbarPolicy="NEVER" fitToHeight="true" minHeight="83.0">
<HBox>
<VBox>
<TitledPane text="Title">
<HBox>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
</HBox>
</TitledPane>
</VBox>
</HBox>
</ScrollPane>
</top>
<center>
</center>
<bottom>
</bottom>
</BorderPane>
看起来像是 ScrollPaneSkin 中的错误 (reported):如果策略为 AS_NEEDED 且滚动条可见,则其 computePrefHeight 方法不会考虑滚动条的高度。
所以解决方法是自定义皮肤 ;) 请注意,如果将策略从始终更改为 AS_NEEDED(在调用 computeXX 时,栏是可见 - 不太清楚为什么),所以我们正在听取政策的变化并隐藏酒吧..粗鲁但有效。
自定义皮肤(注意:不是正式测试!)和驱动程序:
public class ScrollPaneSizing extends Application{
public static class DebugScrollPaneSkin extends ScrollPaneSkin {
public DebugScrollPaneSkin(ScrollPane scroll) {
super(scroll);
registerChangeListener(scroll.hbarPolicyProperty(), p -> {
// rude .. but visibility is updated in layout anyway
getHorizontalScrollBar().setVisible(false);
});
}
@Override
protected double computePrefHeight(double x, double topInset,
double rightInset, double bottomInset, double leftInset) {
double computed = super.computePrefHeight(x, topInset, rightInset, bottomInset, leftInset);
if (getSkinnable().getHbarPolicy() == ScrollBarPolicy.AS_NEEDED && getHorizontalScrollBar().isVisible()) {
// this is fine when horizontal bar is shown/hidden due to resizing
// not quite okay while toggling the policy
// the actual visibilty is updated in layoutChildren?
computed += getHorizontalScrollBar().prefHeight(-1);
}
return computed;
}
}
private Parent createContent() {
HBox inner = new HBox(new Text("somehing horizontal and again again ........"));
TitledPane titled = new TitledPane("my title", inner);
ScrollPane scroll = new ScrollPane(titled) {
@Override
protected Skin<?> createDefaultSkin() {
return new DebugScrollPaneSkin(this);
}
};
scroll.setVbarPolicy(NEVER);
scroll.setHbarPolicy(ALWAYS);
// scroll.setFitToHeight(true);
Button policy = new Button("toggle HBarPolicy");
policy.setOnAction(e -> {
ScrollBarPolicy p = scroll.getHbarPolicy();
scroll.setHbarPolicy(p == ALWAYS ? AS_NEEDED : ALWAYS);
});
HBox buttons = new HBox(10, policy);
BorderPane content = new BorderPane();
content.setTop(scroll);
content.setBottom(buttons);
return content;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent(), 400, 200));
stage.setTitle(FXUtils.version());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
@SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(ScrollPaneSizing.class.getName());
}
我写了一个 openJDK 8 版本,因为接受的答案只适用于 9
public class ScrollPaneHSkin extends ScrollPane
{
ScrollBar hbar;
public ScrollPaneHSkin()
{
super();
}
public ScrollPaneHSkin(Node content)
{
super(content);
}
@Override
protected Skin<?> createDefaultSkin()
{
return new HSkin();
}
private class HSkin extends ScrollPaneSkin
{
HSkin()
{
super(ScrollPaneHSkin.this);
hbarPolicyProperty().addListener((ov, old, current) ->
// rude .. but visibility is updated in layout anyway
hsb.setVisible(false)
);
}
@Override
protected double computePrefHeight(double x, double topInset,
double rightInset, double bottomInset, double leftInset)
{
double computed = super.computePrefHeight(x, topInset, rightInset, bottomInset, leftInset);
if (getSkinnable().getHbarPolicy() == ScrollBarPolicy.AS_NEEDED && hsb.isVisible())
{
// this is fine when horizontal bar is shown/hidden due to resizing
// not quite okay while toggling the policy
// the actual visibilty is updated in layoutChildren?
computed += hsb.prefHeight(-1);
}
return computed;
}
}
}
我将一些内容包装到 ScrollPane 中,因为如果内容不适合屏幕,我需要一个水平滚动条。
只要不需要滚动条就可以了:
然而,当显示滚动条时,它(垂直)隐藏了部分内容:
如何防止这种行为?内容应始终完整显示。我尝试使用 fitToHeight="true"
,但这没有用。
下面是一些示例 FXML(添加了多层 HBox 和 VBox 以模仿我的真实应用程序的结构):
<BorderPane>
<top>
<ScrollPane vbarPolicy="NEVER" fitToHeight="true">
<HBox>
<VBox>
<TitledPane text="Title">
<HBox spacing="100.0">
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
<Text text="Test1 Test2 Test3 Test4"></Text>
</HBox>
</TitledPane>
</VBox>
</HBox>
</ScrollPane>
</top>
<center>
</center>
<bottom>
</bottom>
</BorderPane>
您可以通过将 vbox 的 minHeight 设置为可以完全显示文本的大小来解决这个问题,或者您可以添加填充
例如(填充)
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.ColorPicker?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Text?>
<?import javafx.geometry.Insets?>
<BorderPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<top>
<ScrollPane vbarPolicy="NEVER" fitToHeight="true">
<HBox>
<VBox spacing="100.0">
<TitledPane text="Title">
<HBox>
<children>
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
<Text text="Test1 Test2 Test3 Test4" />
</children>
</HBox>
</TitledPane>
<padding>
<Insets bottom="5.0" top="5.0" />
</padding>
</VBox>
</HBox>
</ScrollPane>
</top>
<center>
</center>
<bottom>
</bottom>
</BorderPane>
例如。 (最小高度)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.*?>
<BorderPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<top>
<ScrollPane vbarPolicy="NEVER" fitToHeight="true" minHeight="83.0">
<HBox>
<VBox>
<TitledPane text="Title">
<HBox>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
<Text text="Test1 Test2 Test3 Test4"/>
</HBox>
</TitledPane>
</VBox>
</HBox>
</ScrollPane>
</top>
<center>
</center>
<bottom>
</bottom>
</BorderPane>
看起来像是 ScrollPaneSkin 中的错误 (reported):如果策略为 AS_NEEDED 且滚动条可见,则其 computePrefHeight 方法不会考虑滚动条的高度。
所以解决方法是自定义皮肤 ;) 请注意,如果将策略从始终更改为 AS_NEEDED(在调用 computeXX 时,栏是可见 - 不太清楚为什么),所以我们正在听取政策的变化并隐藏酒吧..粗鲁但有效。
自定义皮肤(注意:不是正式测试!)和驱动程序:
public class ScrollPaneSizing extends Application{
public static class DebugScrollPaneSkin extends ScrollPaneSkin {
public DebugScrollPaneSkin(ScrollPane scroll) {
super(scroll);
registerChangeListener(scroll.hbarPolicyProperty(), p -> {
// rude .. but visibility is updated in layout anyway
getHorizontalScrollBar().setVisible(false);
});
}
@Override
protected double computePrefHeight(double x, double topInset,
double rightInset, double bottomInset, double leftInset) {
double computed = super.computePrefHeight(x, topInset, rightInset, bottomInset, leftInset);
if (getSkinnable().getHbarPolicy() == ScrollBarPolicy.AS_NEEDED && getHorizontalScrollBar().isVisible()) {
// this is fine when horizontal bar is shown/hidden due to resizing
// not quite okay while toggling the policy
// the actual visibilty is updated in layoutChildren?
computed += getHorizontalScrollBar().prefHeight(-1);
}
return computed;
}
}
private Parent createContent() {
HBox inner = new HBox(new Text("somehing horizontal and again again ........"));
TitledPane titled = new TitledPane("my title", inner);
ScrollPane scroll = new ScrollPane(titled) {
@Override
protected Skin<?> createDefaultSkin() {
return new DebugScrollPaneSkin(this);
}
};
scroll.setVbarPolicy(NEVER);
scroll.setHbarPolicy(ALWAYS);
// scroll.setFitToHeight(true);
Button policy = new Button("toggle HBarPolicy");
policy.setOnAction(e -> {
ScrollBarPolicy p = scroll.getHbarPolicy();
scroll.setHbarPolicy(p == ALWAYS ? AS_NEEDED : ALWAYS);
});
HBox buttons = new HBox(10, policy);
BorderPane content = new BorderPane();
content.setTop(scroll);
content.setBottom(buttons);
return content;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent(), 400, 200));
stage.setTitle(FXUtils.version());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
@SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(ScrollPaneSizing.class.getName());
}
我写了一个 openJDK 8 版本,因为接受的答案只适用于 9
public class ScrollPaneHSkin extends ScrollPane
{
ScrollBar hbar;
public ScrollPaneHSkin()
{
super();
}
public ScrollPaneHSkin(Node content)
{
super(content);
}
@Override
protected Skin<?> createDefaultSkin()
{
return new HSkin();
}
private class HSkin extends ScrollPaneSkin
{
HSkin()
{
super(ScrollPaneHSkin.this);
hbarPolicyProperty().addListener((ov, old, current) ->
// rude .. but visibility is updated in layout anyway
hsb.setVisible(false)
);
}
@Override
protected double computePrefHeight(double x, double topInset,
double rightInset, double bottomInset, double leftInset)
{
double computed = super.computePrefHeight(x, topInset, rightInset, bottomInset, leftInset);
if (getSkinnable().getHbarPolicy() == ScrollBarPolicy.AS_NEEDED && hsb.isVisible())
{
// this is fine when horizontal bar is shown/hidden due to resizing
// not quite okay while toggling the policy
// the actual visibilty is updated in layoutChildren?
computed += hsb.prefHeight(-1);
}
return computed;
}
}
}