我在ScrollPane中缩放和平移图像时遇到问题。到目前为止,我有这样的代码:
Image image = imageView.getImage();
scrollPane.setPrefViewportWidth(0d);
scrollPane.setPrefViewportHeight(0d);
imageView.setFitWidth(0d);
imageView.setFitHeight(0d);
Bounds viewportBounds = scrollPane.getViewportBounds();
boolean vertical = image.getWidth() > image.getHeight();
if (imageView.getRotate() == 90 || imageView.getRotate() == 270d) {
vertical = !vertical;
}
imageView.setPreserveRatio(true);
double propX = viewportBounds.getWidth() / image.getWidth();
double propY = viewportBounds.getHeight() / image.getHeight();
boolean xLead = !(propX > propY);
imageView.setScaleX((xLead) ? propX : propY);
imageView.setScaleY((xLead) ? propX : propY);
scrollPane.setContent(imageView);
scrollPane.setPannable(true);
scrollPane.setHvalue(scrollPane.getHmin() + (scrollPane.getHmax() - scrollPane.getHmin()) / 2); // center the scroll contents.
scrollPane.setVvalue(scrollPane.getVmin() + (scrollPane.getVmax() - scrollPane.getVmin()) / 2);
zoom(imageView);
private void zoom(ImageView imagePannable) {
imagePannable.setOnScroll(
new EventHandler<ScrollEvent>() {
@Override
public void handle(ScrollEvent event) {
double zoomFactor = 1.20;
double deltaY = event.getDeltaY();
if (deltaY < 0) {
zoomFactor = 0.80;
}
imagePannable.setScaleX(imagePannable.getScaleX() * zoomFactor);
imagePannable.setScaleY(imagePannable.getScaleY() * zoomFactor);
event.consume();
}
});
}
我想做的是相对于鼠标指针对齐图像,而不是每次都对齐图像中心。 大图像(例如8 * A4尺寸的地图)也存在问题。缩放此地图时,可缩放功能停止工作。此代码有什么问题?感谢您的帮助!
答案 0 :(得分:3)
几个人(包括我)也有同样的问题。我得到了my answer here。
为清楚起见,这是一个使用矩形作为缩放节点的平移和缩放窗格的工作示例。我已经使用ImageView以稍微复杂的方式实现了这一点。
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.StrokeType;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ZoomAndPanExample extends Application {
private ScrollPane scrollPane = new ScrollPane();
private final DoubleProperty zoomProperty = new SimpleDoubleProperty(1.0d);
private final DoubleProperty deltaY = new SimpleDoubleProperty(0.0d);
private final Group group = new Group();
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage primaryStage) {
scrollPane.setPannable(true);
scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
scrollPane.setVbarPolicy(ScrollBarPolicy.NEVER);
AnchorPane.setTopAnchor(scrollPane, 10.0d);
AnchorPane.setRightAnchor(scrollPane, 10.0d);
AnchorPane.setBottomAnchor(scrollPane, 10.0d);
AnchorPane.setLeftAnchor(scrollPane, 10.0d);
AnchorPane root = new AnchorPane();
Rectangle rect = new Rectangle(80, 60);
rect.setStroke(Color.NAVY);
rect.setFill(Color.NAVY);
rect.setStrokeType(StrokeType.INSIDE);
group.getChildren().add(rect);
// create canvas
PanAndZoomPane panAndZoomPane = new PanAndZoomPane();
zoomProperty.bind(panAndZoomPane.myScale);
deltaY.bind(panAndZoomPane.deltaY);
panAndZoomPane.getChildren().add(group);
SceneGestures sceneGestures = new SceneGestures(panAndZoomPane);
scrollPane.setContent(panAndZoomPane);
panAndZoomPane.toBack();
scrollPane.addEventFilter( MouseEvent.MOUSE_CLICKED, sceneGestures.getOnMouseClickedEventHandler());
scrollPane.addEventFilter( MouseEvent.MOUSE_PRESSED, sceneGestures.getOnMousePressedEventHandler());
scrollPane.addEventFilter( MouseEvent.MOUSE_DRAGGED, sceneGestures.getOnMouseDraggedEventHandler());
scrollPane.addEventFilter( ScrollEvent.ANY, sceneGestures.getOnScrollEventHandler());
root.getChildren().add(scrollPane);
Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
class PanAndZoomPane extends Pane {
public static final double DEFAULT_DELTA = 1.3d;
DoubleProperty myScale = new SimpleDoubleProperty(1.0);
public DoubleProperty deltaY = new SimpleDoubleProperty(0.0);
private Timeline timeline;
public PanAndZoomPane() {
this.timeline = new Timeline(60);
// add scale transform
scaleXProperty().bind(myScale);
scaleYProperty().bind(myScale);
}
public double getScale() {
return myScale.get();
}
public void setScale( double scale) {
myScale.set(scale);
}
public void setPivot( double x, double y, double scale) {
// note: pivot value must be untransformed, i. e. without scaling
// timeline that scales and moves the node
timeline.getKeyFrames().clear();
timeline.getKeyFrames().addAll(
new KeyFrame(Duration.millis(200), new KeyValue(translateXProperty(), getTranslateX() - x)),
new KeyFrame(Duration.millis(200), new KeyValue(translateYProperty(), getTranslateY() - y)),
new KeyFrame(Duration.millis(200), new KeyValue(myScale, scale))
);
timeline.play();
}
public void fitWidth () {
double scale = getParent().getLayoutBounds().getMaxX()/getLayoutBounds().getMaxX();
double oldScale = getScale();
double f = scale - oldScale;
double dx = getTranslateX() - getBoundsInParent().getMinX() - getBoundsInParent().getWidth()/2;
double dy = getTranslateY() - getBoundsInParent().getMinY() - getBoundsInParent().getHeight()/2;
double newX = f*dx + getBoundsInParent().getMinX();
double newY = f*dy + getBoundsInParent().getMinY();
setPivot(newX, newY, scale);
}
public void resetZoom () {
double scale = 1.0d;
double x = getTranslateX();
double y = getTranslateY();
setPivot(x, y, scale);
}
public double getDeltaY() {
return deltaY.get();
}
public void setDeltaY( double dY) {
deltaY.set(dY);
}
}
/**
* Mouse drag context used for scene and nodes.
*/
class DragContext {
double mouseAnchorX;
double mouseAnchorY;
double translateAnchorX;
double translateAnchorY;
}
/**
* Listeners for making the scene's canvas draggable and zoomable
*/
public class SceneGestures {
private DragContext sceneDragContext = new DragContext();
PanAndZoomPane panAndZoomPane;
public SceneGestures( PanAndZoomPane canvas) {
this.panAndZoomPane = canvas;
}
public EventHandler<MouseEvent> getOnMouseClickedEventHandler() {
return onMouseClickedEventHandler;
}
public EventHandler<MouseEvent> getOnMousePressedEventHandler() {
return onMousePressedEventHandler;
}
public EventHandler<MouseEvent> getOnMouseDraggedEventHandler() {
return onMouseDraggedEventHandler;
}
public EventHandler<ScrollEvent> getOnScrollEventHandler() {
return onScrollEventHandler;
}
private EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
sceneDragContext.mouseAnchorX = event.getX();
sceneDragContext.mouseAnchorY = event.getY();
sceneDragContext.translateAnchorX = panAndZoomPane.getTranslateX();
sceneDragContext.translateAnchorY = panAndZoomPane.getTranslateY();
}
};
private EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
panAndZoomPane.setTranslateX(sceneDragContext.translateAnchorX + event.getX() - sceneDragContext.mouseAnchorX);
panAndZoomPane.setTranslateY(sceneDragContext.translateAnchorY + event.getY() - sceneDragContext.mouseAnchorY);
event.consume();
}
};
/**
* Mouse wheel handler: zoom to pivot point
*/
private EventHandler<ScrollEvent> onScrollEventHandler = new EventHandler<ScrollEvent>() {
@Override
public void handle(ScrollEvent event) {
double delta = PanAndZoomPane.DEFAULT_DELTA;
double scale = panAndZoomPane.getScale(); // currently we only use Y, same value is used for X
double oldScale = scale;
panAndZoomPane.setDeltaY(event.getDeltaY());
if (panAndZoomPane.deltaY.get() < 0) {
scale /= delta;
} else {
scale *= delta;
}
double f = (scale / oldScale)-1;
double dx = (event.getX() - (panAndZoomPane.getBoundsInParent().getWidth()/2 + panAndZoomPane.getBoundsInParent().getMinX()));
double dy = (event.getY() - (panAndZoomPane.getBoundsInParent().getHeight()/2 + panAndZoomPane.getBoundsInParent().getMinY()));
panAndZoomPane.setPivot(f*dx, f*dy, scale);
event.consume();
}
};
/**
* Mouse click handler
*/
private EventHandler<MouseEvent> onMouseClickedEventHandler = new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (event.getButton().equals(MouseButton.PRIMARY)) {
if (event.getClickCount() == 2) {
panAndZoomPane.resetZoom();
}
}
if (event.getButton().equals(MouseButton.SECONDARY)) {
if (event.getClickCount() == 2) {
panAndZoomPane.fitWidth();
}
}
}
};
}
}