gpt4 book ai didi

javafx-8 - JavaFX 8 动态节点扩展

转载 作者:行者123 更新时间:2023-12-02 22:11:09 29 4
gpt4 key购买 nike

我正在尝试使用 ScrollPane 实现一个场景,其中用户可以拖动节点并动态缩放它。我可以使用鼠标滚轮进行拖动和缩放以及重置缩放,但在计算以使节点适合父级的宽度时遇到问题。

这是我的代码 sscce

  1. (有效)鼠标滚轮将围绕鼠标指针放大和缩小
  2. (有效)按住鼠标左键或右键拖动矩形周围
  3. (有效)左键双击可重置缩放
  4. (不起作用)右键双击以适应宽度

如果我放大或缩小或更改窗口大小,则宽度调整不起作用。

如果有人可以帮助我计算使节点适合父级的宽度,我将非常感激。

已编辑:

  • 我标记了无法正常工作的方法。它是 fitWidth(),通过双击鼠标右键来调用。
  • 为了清晰和突出重点,我编辑了问题的文本

希望现在这一点更加清楚了。

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();

}

/**
* !!!! The problem is in this method !!!!
*
* The calculations are incorrect, and result in unpredictable behavior
*
*/
public void fitWidth () {
double scale = getParent().getLayoutBounds().getMaxX()/getLayoutBounds().getMaxX();
double oldScale = getScale();

double f = (scale / oldScale)-1;

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

最佳答案

我找到了答案。我正在查看错误的计算,假设它与翻译有关。真正的罪魁祸首是规模差异的计算。我只是改变了这一点:

double f = (scale/oldScale)-1;

对此:

double f = scale - oldScale;

关于javafx-8 - JavaFX 8 动态节点扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29788184/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com