我正在嘗試創建一個處理縮放和平移組件的類。該類包含對我正在使用的 Anchorpane 的參考,因為它默認情況下不進行任何對齊,以及我希望能夠拖動和縮放的 ImageView。縮放和平移都單獨作業,但是一旦放大或縮小影像,我就無法重新居中。
這個想法是我希望能夠在應用程式調整大小時使影像居中,以便拖動總是相對于 Anchorpane 的中心。默認情況下,Anchorpane 中的任何位移都是相對于左上角的,但這對用戶來說并不直觀。內容看起來相對于中心移動會更合乎邏輯。為了實作這一點,我們的想法是在視窗大小改變時重新定位內容,然后應用與用戶所做的拖動量相對應的翻譯
如果您運行我發布的代碼并放大,然后調整視窗大小,您會注意到代表影像的紅色矩形到處都是。如果你縮小視窗,那么正方形將不再和以前一樣在同一個地方。這僅在應用了縮放并且似乎是重新居中方法的問題時才會發生。
如果居中方法正常作業,則正方形應回傳到視窗展開前的相同位置,當正方形處于 1 比 1 比例且未發生縮放時會發生這種情況
這是我用來處理縮放和拖動的類
package com.example.test;
import javafx.beans.value.ChangeListener;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
public class ZoomController{
// the plane on which the node is being dragged
private final AnchorPane PLANE;
// the node I want to zoom and drag
private final Node CONTENT;
private Point2D lastContentPosition = new Point2D(0, 0);
private Point2D lastMousePosition = new Point2D(0, 0);
// the total amount of dragging
// applied to the CONTENT node
private Point2D dragOffset = new Point2D(0, 0);
// the total amount of scaling
// applied to the CONTENT node
private int scale = 1;
public ZoomController(
AnchorPane plane,
Node content
) {
this.PLANE = plane;
this.CONTENT = content;
addListeners();
// artificially reproduces the problem
applyZoom(2, new Point2D(0, 350));
applyDrag(new Point2D(-100, 0));
}
private void addListeners() {
// tries to center the CONTENT whenever the window is resized
PLANE.heightProperty().addListener(centerContent());
PLANE.widthProperty().addListener(centerContent());
// saves the mouse's position whenever the mouse moves
PLANE.setOnMousePressed(getMousePosition());
PLANE.setOnMouseDragged(drag());
PLANE.setOnScroll(handleScroll());
}
private ChangeListener<Number> centerContent() {
return (observableValue, number, t1) -> {
centerView();
};
}
private EventHandler<MouseEvent> drag() {
return mouseEvent -> {
// calculates the path taken by the mouse...
Point2D newMousePosition = new Point2D(mouseEvent.getX(), mouseEvent.getY());
Point2D mouseTranslation = lastMousePosition.subtract(newMousePosition);
// ...and saves its new position
updateMousePosition(mouseEvent);
// applies the drag
applyDrag(mouseTranslation);
};
}
private EventHandler<MouseEvent> getMousePosition() {
return this::updateMousePosition;
}
private EventHandler<ScrollEvent> handleScroll() {
return scrollEvent -> {
// filters out the mouse stopping to scroll
if (scrollEvent.getDeltaX() == 0 && scrollEvent.getDeltaY() == 0) return;
// starts zooming
if (scrollEvent.isControlDown()) {
zoom(scrollEvent);
}
};
}
private void zoom(ScrollEvent scrollEvent) {
// adds or subtracts to the image's scale based on
// whether user is scrolling backwards or forwards
final double dScale = scrollEvent.getDeltaY() > 0 ? 0.1 : -0.1;
scale = dScale;
// gets the coordinates IN THE IMAGE's FRAME OF REFERENCE
// of the point at which to zoom the image so it is centered on the mouse
Point2D target = CONTENT.parentToLocal(new Point2D(scrollEvent.getX(), scrollEvent.getY()));
// applies the zoom to the image
applyZoom(1 dScale, target);
// saves the image's position once it has been zoomed
updateContentPosition();
}
private void applyZoom(final double zoomAmount, Point2D target) {
// applies the necessary scaling to the image...
Scale zoom = new Scale(zoomAmount, zoomAmount);
// ...and centers the scaling to the point where the mouse is located at
zoom.setPivotY(target.getY());
zoom.setPivotX(target.getX());
CONTENT.getTransforms().add(zoom);
updateContentPosition();
}
private void applyDrag(Point2D dragAmount) {
// drag amount always corresponds to the mouse's displacement
// for the moment this is a 1 to 1 mapping
// since I have not figured out how to take the scale into consideration
// updates the total displacement caused by drag (used when we re-center the image)
dragOffset = dragOffset.subtract(dragAmount);
// applies the necessary translation to the image...
Translate drag = new Translate();
// ...based on the mouse's movement
drag.setX(-dragAmount.getX());
drag.setY(-dragAmount.getY());
CONTENT.getTransforms().add(drag);
// saves the image's position after it has been dragged
updateContentPosition();
}
private void centerView() {
// gets the coordinates we need to place the image at for it to be centered
Point2D centerPosition = getCenterEdge();
// calculates the path to take from the image's current position
// to the position it has to be at to be centered
// ie: the displacement vector
Point2D translation = centerPosition.subtract(lastContentPosition);
// applies the necessary translation to the image...
Translate translateToCenter = new Translate();
// ...while account for drag so image is not fully re-centered
translateToCenter.setX(translation.getX() dragOffset.getX());
translateToCenter.setY(translation.getY() dragOffset.getY());
CONTENT.getTransforms().add(translateToCenter);
// saves the image's position after it has been centered
updateContentPosition();
}
private void updateMousePosition(MouseEvent mouseEvent) {
lastMousePosition = new Point2D(mouseEvent.getX(), mouseEvent.getY());
}
private void updateContentPosition() {
// updates the image's position
lastContentPosition = getContentPosition();
}
private Point2D getContentPosition() {
// gets the minimal coordinates of the bounds around the image
// ie: the image's coordinates
Bounds contentBounds = CONTENT.getBoundsInParent();
return new Point2D(contentBounds.getMinX(), contentBounds.getMinY());
}
private Point2D getCenterEdge() {
// gets the size of the image and the anchor pane it is in...
Point2D contentSize = getContentSize();
Point2D availableSpace = getAvailableSpace();
// ...to determine the coordinates at which to place the image for it to be centerd
return new Point2D(
(availableSpace.getX() - contentSize.getX()) / 2,
(availableSpace.getY() - contentSize.getY()) / 2
);
}
private Point2D getContentSize() {
// gets the bounds around the image
Bounds contentBounds = CONTENT.getBoundsInParent();
return new Point2D(contentBounds.getWidth(), contentBounds.getHeight());
}
private Point2D getAvailableSpace() {
// gets the size of the Anchorpane the image is inn
return new Point2D(PLANE.getWidth(), PLANE.getHeight());
}
}
這是我用來測驗縮放的主要課程
package com.example.test;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ZoomMain extends Application {
@Override
public void start(Stage stage) throws Exception {
// the node we want to drag & zoom
Rectangle rectangle = new Rectangle(200, 100);
rectangle.setFill(Color.RED);
// the plane on which the node is being dragged
AnchorPane plane = new AnchorPane();
// adds the node
Scene mainScene = new Scene(plane);
plane.getChildren().add(rectangle);
// handles the zoom
ZoomController zoomController = new ZoomController(
plane,
rectangle
);
stage.setTitle("Zooming test");
stage.setScene(mainScene);
stage.setMinHeight(500);
stage.setMinWidth(500);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我已經嘗試將影像分組以拖動和縮放到一個組中,這將很有用,因為它可以讓我一次包含多個要拖動的節點,但是當我這樣做時,組的內容仍然不可見。
uj5u.com熱心網友回復:
不是在縮放后重新居中內容,而是使用內容的中心點作為縮放樞軸。換句話說,圍繞內容的中心進行縮放。
介紹一個簡單的計算中心的方法:
private Point2D getContentCenter() {
Bounds contentBounds = CONTENT.getBoundsInLocal();
return new Point2D(contentBounds.getCenterX(), contentBounds.getCenterY());
}
并圍繞它進行縮放:
private void zoom(ScrollEvent scrollEvent) {
// adds or subtracts to the image's scale based on
// whether user is scrolling backwards or forwards
final double dScale = scrollEvent.getDeltaY() > 0 ? 0.1 : -0.1;
scale = dScale;
Point2D target = getContentCenter();
// applies the zoom to the image
applyZoom(1 dScale, target);
}
編輯:以下ZoomController實作了在調整窗格大小時圍繞嘴巴位置縮放和內容中心化:
class ZoomController{
// the plane on which the node is being dragged
private final AnchorPane PLANE;
// the node I want to zoom and drag
private final Node CONTENT;
// the total amount of scaling applied to the CONTENT node
private int scale = 1;
private Point2D lastMousePosition = new Point2D(0, 0);
public ZoomController( AnchorPane plane, Node content ) {
PLANE = plane;
CONTENT = content;
PLANE.heightProperty().addListener((obs, number, t1) -> centerView());
PLANE.widthProperty().addListener((obs, number, t1) -> centerView());
// saves the mouse's position whenever the mouse moves
PLANE.setOnMousePressed(event -> updateMousePosition(event));
PLANE.setOnMouseDragged(drag());
PLANE.setOnScroll(handleScroll());
}
private void updateMousePosition(MouseEvent mouseEvent) {
lastMousePosition = new Point2D(mouseEvent.getX(), mouseEvent.getY());
}
private EventHandler<ScrollEvent> handleScroll() {
return scrollEvent -> {
// filters out the mouse stopping to scroll
if (scrollEvent.getDeltaX() == 0 && scrollEvent.getDeltaY() == 0) return;
// starts zooming
if (scrollEvent.isControlDown()) {
zoom(scrollEvent);
}
};
}
private void zoom(ScrollEvent scrollEvent) {
// adds or subtracts to the image's scale based on
// whether user is scrolling backwards or forwards
final double dScale = scrollEvent.getDeltaY() > 0 ? 0.1 : -0.1;
scale = dScale;
// scale around mouse position
Point2D pivot = CONTENT.parentToLocal(new Point2D(scrollEvent.getX(), scrollEvent.getY()));
//applies the zoom to the image
applyZoom(1 dScale, pivot);
}
private void applyZoom(final double zoomAmount, Point2D target) {
// applies the necessary scaling to the image...
Scale zoom = new Scale(zoomAmount, zoomAmount);
// ...and centers the scaling to the point where the mouse is located at
zoom.setPivotY(target.getY());
zoom.setPivotX(target.getX());
CONTENT.getTransforms().add(zoom);
}
private EventHandler<MouseEvent> drag() {
return mouseEvent -> {
// calculates the path taken by the mouse...
Point2D newMousePosition = new Point2D(mouseEvent.getX(), mouseEvent.getY());
Point2D mouseTranslation = lastMousePosition.subtract(newMousePosition);
// ...and saves its new position
updateMousePosition(mouseEvent);
// applies the drag
applyDrag(mouseTranslation);
};
}
private void applyDrag(Point2D dragAmount) {
// applies the necessary translation to the image...
Translate drag = new Translate();
// ...based on the mouse's movement
drag.setX(-dragAmount.getX());
drag.setY(-dragAmount.getY());
CONTENT.getTransforms().add(drag);
}
private void centerView() {
// gets the coordinates we need to place the image at for it to be centered
Point2D centerPosition = CONTENT.parentToLocal(getCenterEdge());
Point2D position = getContentPosition();
Point2D translation = centerPosition.subtract(position);
// applies the necessary translation to the image...
Translate translateToCenter = new Translate();
translateToCenter.setX(translation.getX());
translateToCenter.setY(translation.getY());
CONTENT.getTransforms().add(translateToCenter);
}
private Point2D getContentPosition() {
// gets the minimal coordinates of the bounds around the image
// ie: the image's coordinates
Bounds contentBounds = CONTENT.getBoundsInLocal();
return new Point2D(contentBounds.getMinX(), contentBounds.getMinY());
}
private Point2D getCenterEdge() {
// gets the size of the image and the anchor pane it is in...
Point2D contentSize = getContentSize();
Point2D parentSize = getParentSize();
// ...to determine the coordinates at which to place the image for it to be centered
return new Point2D(
(parentSize.getX() - contentSize.getX()) / 2,
(parentSize.getY() - contentSize.getY()) / 2
);
}
private Point2D getContentSize() {
//BoundsInParent: rectangular bounds of this Node which include its transforms
Bounds contentBounds = CONTENT.getBoundsInParent();
return new Point2D(contentBounds.getWidth(), contentBounds.getHeight());
}
private Point2D getParentSize() {//renamed from getAvailableSpace()
// gets the size of the Anchorpane the image is inn
return new Point2D(PLANE.getWidth(), PLANE.getHeight());
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/416143.html
標籤:
上一篇:有沒有辦法使用用戶在python中輸入的答案?(使用查詢器)
下一篇:檔案上傳反應。無法理解問題
