簡體   English   中英

JavaFx 8 - 相對於鼠標位置縮放/縮放ScrollPane

[英]JavaFx 8 - Scaling / zooming ScrollPane relative to mouse position

我需要相對於鼠標位置放大/縮小滾動窗格。

我目前通過將我的內容包裝在一個組中,並縮放組本身來實現縮放功能。 我使用自定義數據透視創建一個新的Scale對象。 (樞軸設置為鼠標位置)

這適用於組的初始比例為1.0的情況,但之后的縮放不會在正確的方向上縮放 - 我相信這是因為當縮放組時相對鼠標位置會發生變化。

我的代碼:

@Override
public void initialize(URL location, ResourceBundle resources) {

    Delta initial_mouse_pos = new Delta();

    anchorpane.setOnScrollStarted(event -> {
        initial_mouse_pos.x = event.getX();
        initial_mouse_pos.y = event.getY();
    });

    anchorpane.setOnScroll(event -> {
        double zoom_fac = 1.05;
        double delta_y = event.getDeltaY();

        if(delta_y < 0) {
            zoom_fac = 2.0 - zoom_fac;
        }

        Scale newScale = new Scale();
        newScale.setPivotX(initial_mouse_pos.x);
        newScale.setPivotY(initial_mouse_pos.y);
        newScale.setX( content_group.getScaleX() * zoom_fac );
        newScale.setY( content_group.getScaleY() * zoom_fac );

        content_group.getTransforms().add(newScale);

        event.consume();
    });
}

private class Delta { double x, y; }

如何在不同的縮放級別獲得正確的鼠標位置? 是否有一種完全不同的方式來縮放ScrollPane更容易?

這是一個可擴展的,可上傳的 JavaFX ScrollPane:

import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.VBox;

public class ZoomableScrollPane extends ScrollPane {
    private double scaleValue = 0.7;
    private double zoomIntensity = 0.02;
    private Node target;
    private Node zoomNode;

    public ZoomableScrollPane(Node target) {
        super();
        this.target = target;
        this.zoomNode = new Group(target);
        setContent(outerNode(zoomNode));

        setPannable(true);
        setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        setFitToHeight(true); //center
        setFitToWidth(true); //center

        updateScale();
    }

    private Node outerNode(Node node) {
        Node outerNode = centeredNode(node);
        outerNode.setOnScroll(e -> {
            e.consume();
            onScroll(e.getTextDeltaY(), new Point2D(e.getX(), e.getY()));
        });
        return outerNode;
    }

    private Node centeredNode(Node node) {
        VBox vBox = new VBox(node);
        vBox.setAlignment(Pos.CENTER);
        return vBox;
    }

    private void updateScale() {
        target.setScaleX(scaleValue);
        target.setScaleY(scaleValue);
    }

    private void onScroll(double wheelDelta, Point2D mousePoint) {
        double zoomFactor = Math.exp(wheelDelta * zoomIntensity);

        Bounds innerBounds = zoomNode.getLayoutBounds();
        Bounds viewportBounds = getViewportBounds();

        // calculate pixel offsets from [0, 1] range
        double valX = this.getHvalue() * (innerBounds.getWidth() - viewportBounds.getWidth());
        double valY = this.getVvalue() * (innerBounds.getHeight() - viewportBounds.getHeight());

        scaleValue = scaleValue * zoomFactor;
        updateScale();
        this.layout(); // refresh ScrollPane scroll positions & target bounds

        // convert target coordinates to zoomTarget coordinates
        Point2D posInZoomTarget = target.parentToLocal(zoomNode.parentToLocal(mousePoint));

        // calculate adjustment of scroll position (pixels)
        Point2D adjustment = target.getLocalToParentTransform().deltaTransform(posInZoomTarget.multiply(zoomFactor - 1));

        // convert back to [0, 1] range
        // (too large/small values are automatically corrected by ScrollPane)
        Bounds updatedInnerBounds = zoomNode.getBoundsInLocal();
        this.setHvalue((valX + adjustment.getX()) / (updatedInnerBounds.getWidth() - viewportBounds.getWidth()));
        this.setVvalue((valY + adjustment.getY()) / (updatedInnerBounds.getHeight() - viewportBounds.getHeight()));
    }
}

您是否嘗試刪除setOnScrollStarted -event並將其內容移至setOnScroll -event?

這樣做可以減少額外Delta級的需求,並且鼠標位置的計算總是與當前縮放系數相同。

我實現了相同的東西,它的工作方式與描述方式相同。

不知何故這樣:

@Override
public void initialize(URL location, ResourceBundle resources) {

    anchorpane.setOnScroll(event -> {
        double zoom_fac = 1.05;

        if(delta_y < 0) {
            zoom_fac = 2.0 - zoom_fac;
        }

        Scale newScale = new Scale();
        newScale.setPivotX(event.getX);
        newScale.setPivotY(event.getY);
        newScale.setX( content_group.getScaleX() * zoom_fac );
        newScale.setY( content_group.getScaleY() * zoom_fac );

        content_group.getTransforms().add(newScale);

        event.consume();
    });
}

我認為這是這個問題的重復,涉及工作中的相同概念。 如果你真的不在乎它是否相對於你的鼠標變焦,只是更喜歡它放大中心看這個問題。 如果您在下面需要更多幫助評論。

假設您想要具有以下縮放行為:當向前/向后推動鼠標滾輪時,光標下的對象將按比例放大/縮小,光標下的區域現在在縮放區域中居中。 例如。 在指向縮放區域中心左側的位置時向前推動車輪會導致“ 向上移動並向右移動 ”動作。

擴展的事情就像你到目前為止一樣簡單。 棘手的部分是移動動作。 在計算中你必須考慮一些問題:

  1. 您必須計算與光標中心和位置的差異。 您可以通過從鼠標位置(mp)減去中心點(cp)來計算此值。

  2. 如果您的縮放級別為1並且您從中心向左指向50px,則您希望將對象向右移動50px,因為屏幕的1px對應於對象的1px(圖片)。 但是,如果您將對象的大小加倍,則2個屏幕像素等於對象像素。 移動對象時必須考慮這一點,因為翻譯部分總是在縮放部分之前完成。 換句話說,您正在以原始大小移動對象,縮放僅是第二個獨立步驟。

  3. 縮放是如何完成的? 在JavaFX中,您只需設置一些scale-properties,JavaFX將為您完成剩下的工作。 但究竟是什么呢? 重要的是要知道,固定點是在縮放對象時的位置。 如果縮放對象,則會有一個點固定在其位置,而所有其他點都朝向此點移動或從其移動。 正如JavaFX的文檔所說,縮放對象的中心將是固定點。

定義坐標沿此節點的X軸圍繞對象中心縮放的因子。

這意味着您必須確保您的視覺中心點等於JavaFX在縮放對象時使用的點。 如果將對象包裝在容器中,則可以實現此目的。 現在縮放容器而不是對象,並將對象放在容器中以滿足您的需要。

我希望這有幫助。 如果您需要更多幫助,請提供簡短的工作示例項目。

暫無
暫無

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

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