【问题标题】:How to access the Scrollbars of a ScrollPane如何访问 ScrollPane 的滚动条
【发布时间】:2012-09-22 14:23:45
【问题描述】:

我正在尝试获取有关ScrollBar 组件的一些信息,这些组件按标准包含在ScrollPane 中。特别是我有兴趣阅读水平Scrollbarheight。怎么参考?

【问题讨论】:

  • 你的意思是要查看水平滚动条使用了多少垂直像素或者放置在什么位置或者什么?
  • 我想看看ScrollBar的高度是多少垂直像素。

标签: java javafx javafx-8 javafx-2


【解决方案1】:

我认为您可以使用 Node 类的 lookupAll() 方法来查找滚动条。 http://docs.oracle.com/javafx/2/api/javafx/scene/Node.html#lookupAll(java.lang.String)

例如:

package com.test;

import java.util.Set;
import javafx.application.Application;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPaneBuilder;
import javafx.scene.text.Text;
import javafx.scene.text.TextBuilder;
import javafx.stage.Stage;

public class JavaFxScrollPaneTest extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        String longString = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.";
        Text longText = TextBuilder.create().text(longString).build();

        ScrollPane scrollPane = ScrollPaneBuilder.create().content(longText).build();
        primaryStage.setScene(new Scene(scrollPane, 400, 100));
        primaryStage.show();

        Set<Node> nodes = scrollPane.lookupAll(".scroll-bar");
        for (final Node node : nodes) {
            if (node instanceof ScrollBar) {
                ScrollBar sb = (ScrollBar) node;
                if (sb.getOrientation() == Orientation.HORIZONTAL) {
                    System.out.println("horizontal scrollbar visible = " + sb.isVisible());
                    System.out.println("width = " + sb.getWidth());
                    System.out.println("height = " + sb.getHeight());
                }
            }
        }
    }
}
【解决方案2】:

这不是最好的做法,但很有效,

private boolean determineVerticalSBVisible(final ScrollPane scrollPane) {
    try {
        final ScrollPaneSkin skin = (ScrollPaneSkin) scrollPane.getSkin();
        final Field field = skin.getClass().getDeclaredField("vsb");
        field.setAccessible(true);
        final ScrollBar scrollBar = (ScrollBar) field.get(skin);
        field.setAccessible(false);
        return scrollBar.isVisible();
    } catch (final Exception e) {
        e.printStackTrace();
    }
    return false;
}

对水平滚动条使用“hsb”。

最好的问候, 恩里克·盖德斯。

【讨论】:

    【解决方案3】:

    由于上述方法并不适用于所有人(包括我),因此我对其进行了更多调查并找到了问题的根源。

    一般来说,这两种方法都有效,但只有在设置了ScrollPaneskin 属性后。就我而言,在使用 FXMLLoader 加载我的视图后,skin 仍然是 null

    skin 属性尚未初始化的情况下延迟调用(使用一次性侦听器)解决了问题。

    工作样板代码:

    ScrollPane scrollPane;
    // ...
    if (scrollPane.getSkin() == null) {
        // Skin is not yet attached, wait until skin is attached to access the scroll bars
        ChangeListener<Skin<?>> skinChangeListener = new ChangeListener<Skin<?>>() {
            @Override
            public void changed(ObservableValue<? extends Skin<?>> observable, Skin<?> oldValue, Skin<?> newValue) {
                scrollPane.skinProperty().removeListener(this);
                accessScrollBar(scrollPane);
            }
        };
        scrollPane.skinProperty().addListener(skinChangeListener);
    } else {
        // Skin is already attached, just access the scroll bars
        accessScrollBar(scrollPane);
    }
    
    private void accessScrollBar(ScrollPane scrollPane) {
        for (Node node : scrollPane.lookupAll(".scroll-bar")) {
            if (node instanceof ScrollBar) {
                ScrollBar scrollBar = (ScrollBar) node;
                if (scrollBar.getOrientation() == Orientation.HORIZONTAL) {
                    // Do something with the horizontal scroll bar
    
                    // Example 1: Print scrollbar height
                    // System.out.println(scrollBar.heightProperty().get());
    
                    // Example 2: Listen to visibility changes
                    // scrollBar.visibleProperty().addListener((observable, oldValue, newValue) -> {
                    //     if(newValue) {
                    //         // Do something when scrollbar gets visible
                    //     } else {
                    //         // Do something when scrollbar gets hidden
                    //     }
                    // });
                }
                if (scrollBar.getOrientation() == Orientation.VERTICAL) {
                    // Do something with the vertical scroll bar
                }
    
            }
        }
    }
    

    【讨论】:

    • runlater 是不安全的:无法保证 何时 调用它,只是 稍后 可能会或可能不会在附加皮肤后调用。监听 scrollPane 的 skin 属性并在第一次更改后进行查找是安全的。
    • @kleopatra 感谢您的意见!我将代码更新为不使用Platform.runLater(),而是听取skin 属性的更改。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-18
    • 1970-01-01
    • 2021-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多