繁体   English   中英

JavaFX 如何更改 ScrollPane 的滚动量?

[英]JavaFX How do I change the amount by which ScrollPane scrolls?

我需要知道如何更改ScrollPane object 用于上下移动内容的数量。 例如,一个ScrollBar有这两种方法:

scrollBar.setUnitIncrement(10);     
scrollBar.setBlockIncrement(50);  

如何使用ScrollPane而不是ScrollBar做同样的事情?

有同样的问题,无法找到答案。 最后从 Erik 提供的链接中得到了正确的方法,并根据我的需要进行了调整。

由于 scrollPane 本身没有触发“setOnScroll”-Event(可能是因为它在这样做之前被消耗了),我必须在 ScrollPane 的内容上设置 EventHandler:

scrollPane_Content.setContent(vBox_Content);

    vBox_Content.setOnScroll(new EventHandler<ScrollEvent>() {
        @Override
        public void handle(ScrollEvent event) {
            double deltaY = event.getDeltaY()*6; // *6 to make the scrolling a bit faster
            double width = scrollPane_Content.getContent().getBoundsInLocal().getWidth();
            double vvalue = scrollPane_Content.getVvalue();
            scrollPane_Content.setVvalue(vvalue + -deltaY/width); // deltaY/width to make the scrolling equally fast regardless of the actual width of the component
        }
    });

这样做可以直接使用滚动条,也可以使用鼠标滚轮上下滚动。

希望这可以帮助其他正在寻找在 scrollPane 上加快滚动速度的人。

在 ScrollPane 中更快的垂直滚动:

    final double SPEED = 0.01;
    scrollPane.getContent().setOnScroll(scrollEvent -> {
        double deltaY = scrollEvent.getDeltaY() * SPEED;
        scrollPane.setVvalue(scrollPane.getVvalue() - deltaY);
    });

在外部样式表中,您可以执行

.scroll-pane .scroll-bar:vertical {
    -fx-unit-increment: 10 ;
    -fx-block-increment: 50 ;
}

.scroll-pane .scroll-bar:horizontal {
    -fx-unit-increment: 5 ;
    -fx-block-increment: 20 ;
}

例如。 如果您希望它仅应用于单个滚动窗格,请为滚动窗格指定一个 id 等。

这通过查看内容和滚动窗格之间的高度差异来修复滚动,以便滚动的数量相同。

//Fix scroll pane slow scrolling
scrollPane.getContent().setOnScroll(scrollEvent -> {
    double deltaY = scrollEvent.getDeltaY();
    double contentHeight = scrollPane.getContent().getBoundsInLocal().getHeight();
    double scrollPaneHeight = scrollPane.getHeight();
    double diff = contentHeight - scrollPaneHeight;
    if (diff < 1) diff = 1;
    double vvalue = scrollPane.getVvalue();
    scrollPane.setVvalue(vvalue + -deltaY/diff);
});

该差值设置为最小值 1 以防止被零除。

我想要的是简单的设置,它可以在任何地方工作。 由于没有给出好的答案,我自己做了一些研究。 也许该解决方案也会对您有所帮助。

由于我想要平滑滚动,我创建了过渡类:

import javafx.animation.Transition;
import javafx.util.Duration;

public abstract class SmoothishTransition extends Transition {
    private final double mod;
    private final double delta;

    private final static int TRANSITION_DURATION = 200;

    public SmoothishTransition(SmoothishTransition old, double delta) {
        setCycleDuration(Duration.millis(TRANSITION_DURATION));
        setCycleCount(0);
        // if the last transition was moving inthe same direction, and is still playing
        // then increment the modifer. This will boost the distance, thus looking faster
        // and seemingly consecutive.
        if (old != null && sameSign(delta, old.delta) && playing(old)) {
            mod = old.getMod() + 1;
        } else {
            mod = 1;
        }
        this.delta = delta;
    }

    public double getMod() {
        return mod;
    }

    @Override
    public void play() {
        super.play();
        // Even with a linear interpolation, startup is visibly slower than the middle.
        // So skip a small bit of the animation to keep up with the speed of prior
        // animation. The value of 10 works and isn't noticeable unless you really pay
        // close attention. This works best on linear but also is decent for others.
        if (getMod() > 1) {
            jumpTo(getCycleDuration().divide(10));
        }
    }

    private static boolean playing(Transition t) {
        return t.getStatus() == Status.RUNNING;
    }

    private static boolean sameSign(double d1, double d2) {
        return (d1 > 0 && d2 > 0) || (d1 < 0 && d2 < 0);
    }
}

然后这个类负责滚动:

import javafx.animation.Interpolator;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.ScrollEvent;

public class SmoothScroll {

    private final static double BASE_MODIFIER = 1;

    public SmoothScroll(final ScrollPane scrollPane, final Node node) {
        this(scrollPane, node, 160);
    }
    public SmoothScroll(final ScrollPane scrollPane, final Node node, final double baseChange) {
        node.setOnScroll(new EventHandler<ScrollEvent>() {
            private SmoothishTransition transition;

            @Override
            public void handle(ScrollEvent event) {
                if (scrollPane==null) {
                    return;
                }
                double deltaYOrg = event.getDeltaY();
                if (deltaYOrg==0) {
                    return;
                }
                double percents = calculatePercents(deltaYOrg>=0);

                final double startingVValue = scrollPane.getVvalue();

                smoothTransition(
                        startingVValue,
                        getFinalVValue(startingVValue, percents),
                        BASE_MODIFIER * deltaYOrg
                );
            }

            private void smoothTransition(double startingVValue, double finalVValue, double deltaY) {
                Interpolator interp = Interpolator.LINEAR;
                transition = new SmoothishTransition(transition, deltaY) {
                    @Override
                    protected void interpolate(double frac) {
                        scrollPane.setVvalue(
                                interp.interpolate(startingVValue, finalVValue, frac)
                        );
                    }
                };
                transition.play();
            }

            private double getFinalVValue(double startingVValue, double percents) {
                double finalVValueToSet = startingVValue + percents;
                if (finalVValueToSet>1) {
                    return 1d;
                }
                if (finalVValueToSet<0) {
                    return 0d;
                }
                return finalVValueToSet;
            }

            private double calculatePercents(boolean positive) {
                double fullHeight = scrollPane.getContent().getBoundsInLocal().getHeight();
                double viewableHeight = scrollPane.getBoundsInLocal().getHeight();
                double fullChangeInHeight = fullHeight-viewableHeight;
                double percents = baseChange /fullChangeInHeight;
                if (positive) {
                    percents = percents*-1;
                }
                return percents;
            }
        });
    }
}

以及用法:

new SmoothScroll(mainScroll, mainVbox);

或者

new SmoothScroll(mainScroll, mainVbox, 50);

此代码应该可以帮助您入门。

此处发布的所有解决方案都不适合我。 我正在使用 Java 11.0.2,这可能是问题所在。 我修复它的方法是使用以下代码:

final double boost = 0.025;
scrollPane.vvalueProperty().addListener(
    (ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
        //System.out.println("from "+oldValue+" to "+newValue);
        double diff = (double) newValue - (double) oldValue;
        if (almostEqual(diff, boost, 0.00001) || almostEqual(diff, (0 - boost), 0.00001) || almostEqual(diff, 0, 0.000001)) {
            return;
        }
        double newww = scrollPane.getVvalue() + (diff > 0 ? boost : (0 - boost));
        //System.out.println("\tnewww val - "+newww+"; diff - "+diff);
        if (0 < newww && newww < 1) {
            //System.out.println("\tsetting value");
            scrollPane.setVvalue(newww);
        }
    });

使用附加方法比较双打:

public static boolean almostEqual(double a, double b, double eps) {
    return Math.abs(a - b) < eps;
}

你可以使用这个:

scrollPane.getVerticalScrollBar().setUnitIncrement(20);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM