2016-10-03 152 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好点! –

相关问题