Приложение должно отображать содержимое панели прокрутки «быстрее», чтобы увеличить скорость прокрутки.
Вы можете добиться этого, сократив количество отображаемых объектов и / или уменьшив количество вызовов метода repaint (layoutChildren в JFX). Насколько я понимаю, фрагмент кода вы собирались уменьшить количество перекрашиваний, потому что изменение параметров приращения позволяет перерисовывать содержимое реже.
blockIncrement
(если щелкнуть трек панели)
unitIncrement
(при нажатии кнопок «Вверх», «Вниз», «Вправо», «Влево»)
При нажатии кнопок панели прокрутки вызывается метод ScrollPane.layoutChildren()
.
Это делает шаги сброса ScrollBar (ScrollPaneSkin.updateVerticalSB(), ScrollPaneSkin.updateHorizontalSB()
).
Поэтому вам нужно сохранить предыдущие значения приращения и отфильтровать события прокрутки «из коробки».
* Источник: 1016 *
public class UnitIncrementScrollPaneSkin extends ScrollPaneSkin {
private double prevVerticalBlockIncrement;
private double prevHorizontalBlockIncrement;
private double prevVerticalUnitIncrement;
private double prevHorizontalUnitIncrement;
public UnitIncrementScrollPaneSkin(final ScrollPane scrollPane) {
super(scrollPane);
filterScrollEvents();
}
@Override
protected void layoutChildren(final double x, final double y, final double w, final double h) {
prevVerticalUnitIncrement = getVerticalScrollBar().getUnitIncrement();
prevHorizontalUnitIncrement = getHorizontalScrollBar().getUnitIncrement();
prevVerticalBlockIncrement = getVerticalScrollBar().getBlockIncrement();
prevHorizontalBlockIncrement = getHorizontalScrollBar().getBlockIncrement();
super.layoutChildren(x, y, w, h);
getVerticalScrollBar().setUnitIncrement(prevVerticalUnitIncrement);
getHorizontalScrollBar().setUnitIncrement(prevHorizontalUnitIncrement);
getVerticalScrollBar().setBlockIncrement(prevVerticalBlockIncrement);
getHorizontalScrollBar().setBlockIncrement(prevHorizontalBlockIncrement);
}
private void filterScrollEvents() {
getSkinnable().addEventFilter(ScrollEvent.SCROLL, event -> {
if (event.getDeltaX() < 0) {
getHorizontalScrollBar().increment();
} else if (event.getDeltaX() > 0) {
getHorizontalScrollBar().decrement();
}
if (event.getDeltaY() < 0) {
getVerticalScrollBar().increment();
} else if (event.getDeltaY() > 0) {
getVerticalScrollBar().decrement();
}
event.consume();
});
}
public ScrollBar getVerticalScrollBar() {
return vsb;
}
public ScrollBar getHorizontalScrollBar() {
return hsb;
}
}
Использование:
@FXML
public void initialize() {
final double initialInc = 0.2;
UnitIncrementScrollPaneSkin skin = new UnitIncrementScrollPaneSkin(scrollPane);
skin.getVerticalScrollBar().setUnitIncrement(initialInc);
skin.getVerticalScrollBar().setBlockIncrement(initialInc);
skin.getHorizontalScrollBar().setUnitIncrement(initialInc);
skin.getHorizontalScrollBar().setBlockIncrement(initialInc);
scrollPane.setSkin(skin);
}
Тестовое приложение:
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="226.0" prefWidth="215.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.stackoverflow.app.scrollpane.SpeedUpScrollPaneController">
<children>
<ScrollPane fx:id="scrollPane" fitToHeight="true" fitToWidth="true" hbarPolicy="ALWAYS" prefHeight="200.0" prefWidth="200.0" vbarPolicy="ALWAYS">
<content>
<GridPane>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
</content>
</ScrollPane>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<Label text="V:" />
<Spinner fx:id="spinnerVertical" prefHeight="25.0" prefWidth="85.0">
<valueFactory>
<SpinnerValueFactory.DoubleSpinnerValueFactory amountToStepBy="0.1" max="1.0" min="0" />
</valueFactory>
</Spinner>
</children>
</HBox>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<Label text="H:" />
<Spinner fx:id="spinnerHorizontal" prefHeight="25.0" prefWidth="85.0">
<valueFactory>
<SpinnerValueFactory.DoubleSpinnerValueFactory amountToStepBy="0.1" max="1.0" min="0" />
</valueFactory>
</Spinner>
</children>
</HBox>
<ListView fx:id="listViewLog" prefHeight="200.0" prefWidth="200.0" />
</children>
</VBox>
public class SpeedUpScrollPaneController {
@FXML
private ListView<String> listViewLog;
@FXML
private Spinner<Double> spinnerVertical;
@FXML
private Spinner<Double> spinnerHorizontal;
@FXML
private ScrollPane scrollPane;
@FXML
public void initialize() {
mockScrollPane();
initScrollPane();
}
private void mockScrollPane() {
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) {
final Label label = new Label(i + "," + j);
label.setMinWidth(60);
label.setMinHeight(30);
((GridPane) scrollPane.getContent()).add(label, i, j);
}
}
}
private void initScrollPane() {
final UnitIncrementScrollPaneSkin skin = new UnitIncrementScrollPaneSkin(scrollPane);
scrollPane.setSkin(skin);
initIncrement(0.2, spinnerHorizontal, skin.getHorizontalScrollBar());
initIncrement(0.2, spinnerVertical, skin.getVerticalScrollBar());
}
private void initIncrement(final double increment, final Spinner<Double> spinner, final ScrollBar scrollBar) {
scrollBar.unitIncrementProperty().addListener((source, prev, curr) -> {
final String vLog = String.format("%tr: %s unitIncrement=%f", Calendar.getInstance(),
scrollBar.getOrientation(), curr);
listViewLog.getItems().add(vLog);
listViewLog.scrollTo(vLog);
});
scrollBar.blockIncrementProperty().addListener((source, prev, curr) -> {
final String vLog = String.format("%tr: %s blockIncrement=%f", Calendar.getInstance(),
scrollBar.getOrientation(), curr);
listViewLog.getItems().add(vLog);
listViewLog.scrollTo(vLog);
});
spinner.valueProperty().addListener((source, prev, curr) -> {
scrollBar.setUnitIncrement(curr);
scrollBar.setBlockIncrement(curr);
});
Platform.runLater(() -> {
scrollBar.setUnitIncrement(increment);
scrollBar.setBlockIncrement(increment);
spinner.getValueFactory().setValue(scrollBar.getUnitIncrement());
});
}
}
- 0.0 -> без прокрутки
- 0.1 -> прокрутка на 10%
- 0,5 -> прокрутка на 50%
- 1.0 -> прокрутка на 100%
- Screencast
PS.
Если у вас есть много объектов для прокрутки, вы можете попробовать подход:
- Создание растрового изображения, представляющего содержимое панели прокрутки
- Показать растровое изображение при прокрутке при старте
- Переместить изображение в X, Y (на основе
ScrollEvent.getDeltaX()
, ScrollEvent.getDeltaY()
)
- Скрыть изображение, показать узлы панели прокрутки с новыми координатами при завершении прокрутки