2016-10-03 151 views
4

我需要在滾動窗格上放大/縮小相對於鼠標位置。JavaFx 8 - 相對於鼠標位置縮放/縮放ScrollPane

我目前通過將我的內容封裝在一個組中並縮放組本身來實現縮放功能。我使用自定義透視創建了一個新的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的方法更容易?

+0

這裏是[I使用的代碼(http://stackoverflow.com/questions/29788184/javafx-8-dynamic-node-scaling)進行動態節點縮放。 – RonSiven

回答

0

我認爲這是this問題的重複,它涉及到工作中的相同概念。如果你真的不在意它是否相對於你的鼠標進行縮放,只是喜歡它放大中心看this問題。如果您在下面需要更多幫助評論。

0

假設您想要具有以下縮放行爲: 向前/向後推動鼠標滾輪時,光標下方的對象將按比例放大/縮小,光標下方的區域現居中放大區域內。例如,向前推動輪子同時指向從縮放區域中心左側的位置導致'放大並向右移動'的操作。

縮放比例和迄今爲止所做的一樣簡單。 棘手的部分是移動動作。有一些問題,你有你的計算中考慮:

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

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

  3. 如何完成縮放?在JavaFX中,您只需設置一些縮放屬性,而JavaFX則爲您完成其餘的工作。但究竟是什麼呢?重要的是要知道的是,在固定點放大對象的情況下。如果您縮放一個物體,則會有一個點保持固定在其位置,而其他所有點都朝此點移動或移動。 由於JavaFX的文檔說縮放對象的中心將是固定點。

定義由該座標被縮放有關 沿着該節點的X軸的對象的中心的因素。

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

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

0

你嘗試刪除setOnScrollStarted -event並移動其內容的setOnScroll -event?

這樣做可以減少額外的需要Delta -class,並且鼠標位置的計算始終與當前縮放係數一致。

我實現了同樣的事情,它的工作原理與你描述的一樣。

不知何故這樣的:

@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

這是一個可擴展的,可平移 JavaFX的滾動窗格:

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())); 
    } 
} 
+1

太棒了,爲我工作。另外:我建議在'if(e.isControlDown()){...}'中包裝'outerNode.setOnScroll(e - > {...}'的內容,這樣可以向上滾動向下保存。 – Poohl

+0

@Poohl好點! –

相關問題