如何增加JavaFX ScrollPane的滚动速度

6

你好,有没有办法提高滚动速度?我找到了一些解决方案,但都没有对我起作用。这是我尝试过的:

@FXML
private ScrollPane scrollPane;

@FXML
public void initialize() {
    Platform.runLater(() -> setFasterScroller(scrollPane));
}

private static void setFasterScroller(ScrollPane scrollPane) {
    ScrollBar verticalScrollbar = (ScrollBar) scrollPane.lookup(".scroll-bar:vertical");
    double defaultUnitIncrement = verticalScrollbar.getUnitIncrement();
    verticalScrollbar.setUnitIncrement(defaultUnitIncrement * 3);
}

或者可以使用CSS:

.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 ;
}

还有其他方法吗? 编辑: 上述的解决方案都没有起作用,我尝试使用非常大的数字,但滚动速度仍然相同。


1
当你说“它们都对我没用”时,是指完全没有效果还是需要更快的速度?无论哪种情况,请编辑你的问题并包含一个 [mcve] 来展示你所描述的问题。 - trashgod
当改变传递给setBlockIncrement()STEP_INCREMENT时,我看到了这个示例中的明显变化。 - trashgod
1个回答

1
该应用程序应该更快地呈现滚动窗格内容,以增加滚动速度。您可以通过减少要呈现的对象数量和/或减少'repaint'方法调用次数(在JFX中的layoutChildren中)来实现。就我理解代码片段而言,您打算减少重新绘制的次数,因为更改增量参数允许较少次数地重新绘制内容。
  • blockIncrement(如果单击了栏的轨道)
  • unitIncrement(如果单击了上、下、左、右按钮)

当您单击滚动窗格按钮时,会调用ScrollPane.layoutChildren()方法。它使ScrollBar重置增量(ScrollPaneSkin.updateVerticalSB(),ScrollPaneSkin.updateHorizontalSB())。因此,您需要存储以前的增量值并过滤“开箱即用”的滚动事件。

来源:

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%
  • 演示视频

PS. 如果您有很多需要滚动的对象,可以尝试以下方法:

  • 创建表示滚动窗格内容的图像位图
  • 开始滚动时显示图像位图
  • 根据 ScrollEvent.getDeltaX()ScrollEvent.getDeltaY() 移动图像的 X、Y 坐标
  • 在完成滚动后隐藏图像,显示新坐标下的滚动窗格节点

1
就像他所说的那样,它只有在您点击滚动条顶部和底部的上下按钮时才能起作用。由于您在问题中没有明确说明需要加快滚轮或按钮的速度,因此您不能假设人们会知道这一点。 - Matt
@Petr M 让我们澄清一下加速的含义。就你的问题而言(据我所知),它意味着更改增量\减量步骤。我添加了 blockIncrement,以防止轨道被点击(答案已更新)。也许你是在谈论拖动操作中的“加速”?请检查新的 blockIncrement 实现,并更详细地描述“加速”这个术语。 - Oleks
我原本以为使用滚轮滚动时,滚动条会更快地移动,但当我尝试实现你的解决方案时,我并没有看到这种情况发生。 - Petr M
@Petr M 请查看 filterScrollEvents 方法。 使用鼠标滚轮滚动将像使用上下按钮一样快地移动滚动条。 - Oleks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接