What I wanted was simple setting, that would work everywhere. Since no good answer was given I did a bit of research on my own. Maybe the solution will help you too.
Since I wanted smooth scrolling, I created transition class:
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);
}
}
Then this class takes care of scrolling:
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;
}
});
}
}
And the usage:
new SmoothScroll(mainScroll, mainVbox);
or
new SmoothScroll(mainScroll, mainVbox, 50);
This code should get you started.