Zoomen in JavaFx: ScrollEvent verbraucht wird, wenn der Inhalt größer als ScrollPane-viewport

Ich habe eine Anwendung, die erfordert zoom innerhalb einer ScrollPane, aber mit meinem jetzigen Ansatz bin ich noch vor 2 Herausforderungen. Um das problem zu replizieren, die ich geschrieben habe eine kleine Anwendung ZoomApp, dass Sie finden den code für darunter. Seine " eingeschränkte Funktionalität ermöglicht das vergrößern und verkleinern (Strg + Mausrad) auf den beliebigen Formen. Wenn der Zoom-Inhalte wächst außerhalb der Grenzen des Fensters Bildlaufleisten sollten apperar.

Herausforderung 1.
Wenn der scroll-Balken erscheint als Folge von innerGroup Skalen in der Größe, die ScrollEvent nicht mehr erreichen, meine ZoomHandler. Stattdessen starten wir nach unten scrollen Sie das Fenster, bis es den Boden erreicht, die beim Zoomen wieder funktioniert, wie erwartet. Ich dachte, vielleicht

scrollPane.setPannable(false);

würde einen Unterschied machen, aber Nein. Wie soll das unerwünschte Verhalten vermieden werden?

Herausforderung 2.
Wie würde ich mich über center innerGroup innerhalb der scrollPane, ohne auf die Farbe eines pixels in der linken oberen Ecke des innerGroup mit der gewünschten delta zu den Plätzen?

Nebenbei, nach der JavaDoc für Bildlauffensters verschoben: "Wenn eine Anwendung will das scrollen auf der Basis der visuellen Grenzen des Knotens (für skalierte Inhalte, etc.), Sie müssen wickeln Sie die scroll-Knoten in einer Gruppe". Dies ist der Grund, warum ich habe ein innerGroup und eine outerGroup innen ScrollPane.

Anregungen, führt mich zu der Lösung wird sehr geschätzt von diesem JavaFX Anfänger.

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SceneBuilder;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

/**
 * Demo of a challenge I have with zooming inside a {@code ScrollPane}.
 * <br>
 * I am running JavaFx 2.2 on a Mac. {@code java -version} yields:
 * <pre>
 * java version "1.7.0_09"
 * Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
 * Java HotSpot(TM) 64-Bit Server VM (build 23.5-b02, mixed mode)
 * </pre>
 * 6 rectangles are drawn, and can be zoomed in and out using either
 * <pre>
 * Ctrl + Mouse Wheel
 * or Ctrl + 2 fingers on the pad.
 * </pre>
 * It reproduces a problem I experience inside an application I am writing.
 * If you magnify to {@link #MAX_SCALE}, an interesting problem occurs when you try to zoom back to {@link #MIN_SCALE}. In the beginning
 * you will see that the {@code scrollPane} scrolls and consumes the {@code ScrollEvent} until we have scrolled to the bottom of the window.
 * Once the bottom of the window is reached, it behaves as expected (or at least as I was expecting).
 *
 * @author Skjalg Bjørndal
 * @since 2012.11.05
 */
public class ZoomApp extends Application {

    private static final int WINDOW_WIDTH = 800;
    private static final int WINDOW_HEIGHT = 600;

    private static final double MAX_SCALE = 2.5d;
    private static final double MIN_SCALE = .5d;

    private class ZoomHandler implements EventHandler<ScrollEvent> {

        private Node nodeToZoom;

        private ZoomHandler(Node nodeToZoom) {
            this.nodeToZoom = nodeToZoom;
        }

        @Override
        public void handle(ScrollEvent scrollEvent) {
            if (scrollEvent.isControlDown()) {
                final double scale = calculateScale(scrollEvent);
                nodeToZoom.setScaleX(scale);
                nodeToZoom.setScaleY(scale);
                scrollEvent.consume();
            }
        }

        private double calculateScale(ScrollEvent scrollEvent) {
            double scale = nodeToZoom.getScaleX() + scrollEvent.getDeltaY() / 100;

            if (scale <= MIN_SCALE) {
                scale = MIN_SCALE;
            } else if (scale >= MAX_SCALE) {
                scale = MAX_SCALE;
            }
            return scale;
        }
    }

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

    @Override
    public void start(Stage stage) throws Exception {

        final Group innerGroup = createSixRectangles();
        final Group outerGroup = new Group(innerGroup);

        final ScrollPane scrollPane = new ScrollPane();
        scrollPane.setContent(outerGroup);
        scrollPane.setOnScroll(new ZoomHandler(innerGroup));

        StackPane stackPane = new StackPane();
        stackPane.getChildren().add(scrollPane);

        Scene scene = SceneBuilder.create()
                .width(WINDOW_WIDTH)
                .height(WINDOW_HEIGHT)
                .root(stackPane)
                .build();

        stage.setScene(scene);
        stage.show();
    }

    private Group createSixRectangles() {
        return new Group(
                createRectangle(0, 0), createRectangle(110, 0), createRectangle(220, 0),
                createRectangle(0, 110), createRectangle(110, 110), createRectangle(220, 110),
                createRectangle(0, 220), createRectangle(110, 220), createRectangle(220, 220)
        );
    }

    private Rectangle createRectangle(int x, int y) {
        Rectangle rectangle = new Rectangle(x, y, 100, 100);
        rectangle.setStroke(Color.ORANGERED);
        rectangle.setFill(Color.ORANGE);
        rectangle.setStrokeWidth(3d);
        return rectangle;
    }
}
InformationsquelleAutor Skjalg | 2012-11-05
Schreibe einen Kommentar