簡體   English   中英

JavaFX - 按下按鈕時滾動scrollPane

[英]JavaFX - scroll a scrollPane while button pressed

我有一個scrollPane,可以通過按下按鈕滾動,使用以下代碼

@FXML
public void scrollUp(ActionEvent event) {
    if (scrollPane.getVvalue() > scrollPane.getVmin()) {
        scrollPane.setVvalue(scrollPane.getVvalue() - scrollPaneIncrement);
    }
}

@FXML
public void scrollDown(ActionEvent event) {
    if (scrollPane.getVvalue() < scrollPane.getVmax()) {
        scrollPane.setVvalue(scrollPane.getVvalue() + scrollPaneIncrement);
    }
}

按下按鈕時,將從onAction事件調用這些函數。

現在,只要按下按鈕,我就需要上下滾動scrollPane。

有誰知道如何去做?

使用AnimationTimer更新每個渲染幀上的滾動位置。 您可以使用isArmed()方法檢查按鈕是否被按下,並相應地更新滾動條的值。

這是一個SSCCE:

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class ScrollWhileButtonDown extends Application {

    @Override
    public void start(Stage primaryStage) {
        ScrollPane scroller = new ScrollPane();
        Pane pane = new Pane();
        pane.setMinHeight(1000);
        scroller.setContent(pane);

        Button upButton = new Button("Up");
        Button downButton = new Button("Down");

        HBox controls = new HBox(10, upButton, downButton);
        controls.setPadding(new Insets(10));
        controls.setAlignment(Pos.CENTER);

        Scene scene = new Scene(new BorderPane(scroller, null, null, controls, null), 600, 400);
        primaryStage.setScene(scene);
        primaryStage.show();

        final double scrollSpeed = 0.5 ; // scrollpane units per second

        AnimationTimer timer = new AnimationTimer() {

            private long lastUpdate = 0 ;
            @Override
            public void handle(long time) {
                if (lastUpdate > 0) {
                    long elapsedNanos = time - lastUpdate ;
                    double elapsedSeconds = elapsedNanos / 1_000_000_000.0 ;
                    double delta = 0 ;
                    if (upButton.isArmed()) {
                        delta = -scrollSpeed * elapsedSeconds ;
                    }
                    if (downButton.isArmed()) {
                        delta = scrollSpeed * elapsedSeconds ;
                    }
                    double newValue = 
                            clamp(scroller.getVvalue() + delta, scroller.getVmin(), scroller.getVmax());
                    scroller.setVvalue(newValue);
                }
                lastUpdate = time ;
            }
        };

        timer.start();
    }

    private double clamp(double value, double min, double max) {
        return Math.min(max, Math.max(min, value));
    }

    public static void main(String[] args) {
        launch(args);
    }
}

以下是我使用ReactFX (版本2.0-M2或更高版本)對@ James_D的回答的變體。 雖然它不是更簡潔,但如果您熟悉EventStream ,則可能更容易閱讀。 它具有額外的好處,即(隱藏的)動畫計時器僅在按下其中一個按鈕時觸發,而不是一直觸發。 這是通過在沒有按下按鈕時切換到觀察特殊流never()的技巧來實現的,這不會導致運行時成本。 不滾動時,您可以觀察到略低的CPU使用率。

import static org.reactfx.EventStreams.*;
import static org.reactfx.util.Tuples.*;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

import org.reactfx.EventStream;

public class ScrollWhileButtonDown extends Application {

    private static enum BTN { UP, DOWN, NONE }

    private static final double scrollSpeed = 0.5 ; // scrollpane units per second

    @Override
    public void start(Stage primaryStage) {
        ScrollPane scroller = new ScrollPane();
        Pane pane = new Pane();
        pane.setMinHeight(1000);
        scroller.setContent(pane);

        Button upButton = new Button("Up");
        Button downButton = new Button("Down");

        HBox controls = new HBox(10, upButton, downButton);
        controls.setPadding(new Insets(10));
        controls.setAlignment(Pos.CENTER);

        Scene scene = new Scene(new BorderPane(scroller, null, null, controls, null), 600, 400);
        primaryStage.setScene(scene);
        primaryStage.show();

        EventStream<BTN> armedButtons = merge(
                valuesOf(upButton  .armedProperty()).map(armed -> armed ? BTN.UP   : BTN.NONE),
                valuesOf(downButton.armedProperty()).map(armed -> armed ? BTN.DOWN : BTN.NONE));

        EventStream<Double> deltas = armedButtons.flatMap(btn -> {
            switch(btn) {
                case UP:   return elapsedSeconds().map(sec -> sec * -scrollSpeed);
                case DOWN: return elapsedSeconds().map(sec -> sec *  scrollSpeed);
                default:   return never();
            }
        });

        deltas.subscribe(delta -> scroller.setVvalue(scroller.getVvalue() + delta));
    }

    private static EventStream<Double> elapsedSeconds() {
        return animationTicks()
                .accumulate(t(0L, -1L), (state, now) -> state.map((d, last) -> {
                        return t(last == -1L ? 0L : now - last, now);
                }))
                .map(t -> t._1 / 1_000_000_000.0);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM