问题描述
我需要相对于鼠标位置放大/缩小滚动窗格。
I need to zoom in / out on a scroll pane, relative to the mouse position.
我目前通过将内容包装在一个组中来实现缩放功能,并扩大集团本身。我使用自定义数据透视创建一个新的Scale对象。 (枢轴设置为鼠标位置)
I currently achieve the zooming functionality by wrapping my content in a Group, and scaling the group itself. I create a new Scale object with a custom pivot. (Pivot is set to the mouse position)
这适用于组初始比例为1.0的情况,但之后的缩放不能按正确的方向缩放 - 我相信这是因为当缩放组时相对鼠标位置会发生变化。
This works perfectly for where the Group's initial scale is 1.0, however scaling afterwards does not scale in the correct direction - I believe this is because the relative mouse position changes when the Group has been scaled.
我的代码:
@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更容易?
How do I get the correct mouse position at different levels of scaling? Is there a completely different way to zooming the ScrollPane that is easier?
推荐答案
这是一个可扩展,可平移的 JavaFX ScrollPane:
This is a scalable, pannable 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()));
}
}
这篇关于JavaFx 8 - 相对于鼠标位置缩放/缩放ScrollPane的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!