JavaFX ScrollBar error

I have a simple JavaFX application with Canvas and ScrollBar. Canvas acts like a virtualized canvas whose content can be scrolled using a ScrollBar.

The canvas width is 500 pixels, but the logical canvas width is 1000 pixels. I set the ScrollBar max to 1000 and the ScrollBar value to 500. The problem is that when the ScrollBar scrolls all the way to the right, the ScrollBar value is 1000, not 500. Logically, when the ScrollBar scrolls all the way to the right, there must be some way to determine the actual scrollable offset and this is not possible. Please tell me how you can get the required amount of scrolling. Thanks you

Here's an example scrolling all the way to the left. The scrollbar looks good. Its visible width is 50% of the window size.

enter image description here

Here's an example scrolling halfway to the right. The problem is clear here. The canvas scrolls 500px to the right, but if the canvas scrolls halfway correctly, it will only scroll 250px.

enter image description here

Here's an example, scrolled all the way to the right. enter image description here

import javafx.application.Application;
import javafx.beans.value.*;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.ScrollBar;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.stage.Stage;

public class Sc extends Application {

    public ScrollBar scrollBar;
    double scrolled;
    Canvas canvas;

    @Override
    public void start(Stage stage) {
        VBox vbox = new VBox();
        Scene scene = new Scene(vbox);
        stage.setScene(scene);

        canvas = new Canvas(500, 100);
        scrollBar = new ScrollBar();
        scrollBar.setMin(0);
        scrollBar.setMax(1000);
        scrollBar.setVisibleAmount(500);
        vbox.getChildren().addAll(canvas, scrollBar);
        draw();

        scrollBar.valueProperty().addListener(new ChangeListener<Number>() {
            public void changed(ObservableValue<? extends Number> ov,
                Number old_val, Number new_val) {
                scrolled = new_val.doubleValue();
                draw();
            }
        });

        stage.show();
    }

    private void draw()
    {
        GraphicsContext graphics = canvas.getGraphicsContext2D();
        graphics.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
        Stop[] stops = new Stop[] { new Stop(0, Color.BLACK), new Stop(1, Color.RED)};
        LinearGradient lg = new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, stops);
        graphics.setFill(lg);
        graphics.fillRect(0-scrolled, 30, 1000, 40);
    }

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

      

+3


source to share


1 answer


Think of it this way:

min

, max

and value

are the boolean values โ€‹โ€‹of the scrollbar. value

is between min

and max

and is equal min

if and only if the scrollbar scroll is fully scrolled to the left (or top, for a vertical scrollbar). It is equal to max if and only if the scrollbar is scrolled as far to the right (or bottom) as possible.

A property visibleAmount

is simply a visual property that determines the size of the thumb. This relationship is similar to

thumbSize / trackSize = visibleAmount / (max - min)

      



visibleAmount

will affect the relationship between actual pixels and "logical units"; however, this does not change the fact that it value

can vary over the entire range [min, max]

.

Thus, the only change you need to make to your code is to set the maximum value of the scrollbar to the maximum value that can be scrolled (not the size of the image you are drawing), which is 1000 - canvas.getWidth()

:

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.ScrollBar;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.stage.Stage;

public class ScrollBarExample extends Application {

    private final static double TOTAL_WIDTH = 1000 ;


    @Override
    public void start(Stage stage) {
        VBox vbox = new VBox();

        Scene scene = new Scene(vbox, 500, 130);
        stage.setScene(scene);

        Canvas canvas = new Canvas(500, 100);
        ScrollBar scrollBar = new ScrollBar();
        scrollBar.setMin(0);
        scrollBar.setMax(TOTAL_WIDTH - canvas.getWidth());

        scrollBar.setVisibleAmount(scrollBar.getMax() * canvas.getWidth() / TOTAL_WIDTH);

        vbox.getChildren().addAll(canvas, scrollBar);
        draw(canvas, scrollBar.getValue());

        scrollBar.valueProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> ov,
                Number old_val, Number new_val) {
                draw(canvas, scrollBar.getValue());
            }
        });


        stage.show();
    }

    private void draw(Canvas canvas, double scrollAmount)
    {
        GraphicsContext graphics = canvas.getGraphicsContext2D();
        graphics.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
        Stop[] stops = new Stop[] { new Stop(0, Color.BLACK), new Stop(1, Color.RED)};
        LinearGradient lg = new LinearGradient(0, 0, 1, 0, true, CycleMethod.NO_CYCLE, stops);
        graphics.setFill(lg);
        graphics.fillRect(0-scrollAmount, 30, TOTAL_WIDTH, 40);
    }

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

      

+3


source







All Articles