Reputation: 2272
I need to know how to change the amount that a ScrollPane
object use to move the content up and down. For example, a ScrollBar
have these two methods for that:
scrollBar.setUnitIncrement(10);
scrollBar.setBlockIncrement(50);
How do I do the same with a ScrollPane
instead of ScrollBar
?
Upvotes: 6
Views: 7956
Reputation: 1
None of the solutions posted here worked for me. I'm using Java 11.0.2, that might be the issue. The way I fixed it is with this code:
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);
}
});
Using additional method for comparison of doubles:
public static boolean almostEqual(double a, double b, double eps) {
return Math.abs(a - b) < eps;
}
Upvotes: 0
Reputation: 484
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.
Upvotes: 0
Reputation: 3294
This fixes the scrolling by looking at the difference in height between the content and the scroll pane so that the amount scrolled is the same.
//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);
});
The difference is set to a minimum value of 1 to prevent divide by zero.
Upvotes: 3
Reputation: 1644
Faster vertical scroll in a ScrollPane:
final double SPEED = 0.01;
scrollPane.getContent().setOnScroll(scrollEvent -> {
double deltaY = scrollEvent.getDeltaY() * SPEED;
scrollPane.setVvalue(scrollPane.getVvalue() - deltaY);
});
Upvotes: 7
Reputation: 69
Had the same question and was unable to find the answer. Finally got the correct approach from the link provided by Erik and adapted it to my needs.
As the scrollPane itself did not fire the "setOnScroll"-Event (possibly because it gets consumed before doing so), I had to set the EventHandler on the content of the ScrollPane:
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
}
});
Doing so works with using the scrollbar directly as well as using the mousewheel to scroll up and down.
Hope this helps others who are looking for speeding up scrolling on a scrollPane.
Upvotes: 6
Reputation: 209684
In an external style sheet you can do
.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 ;
}
for example. If you want it to apply to just a single scroll pane, give the scroll pane an id, etc.
Upvotes: 5
Reputation: 14657
You can use this:
scrollPane.getVerticalScrollBar().setUnitIncrement(20);
Upvotes: -3