gpt4 book ai didi

java - 在可平移/可缩放 Pane 中选取并移动节点

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:22:22 26 4
gpt4 key购买 nike

我正在尝试将一些组件放置在 ScrollPane 中。这些组件应该能够通过鼠标(单击并拖动)在该 Pane 中移动。 ScrollPane 本身可平移和缩放。

现在,如果我选择其中一个并将其拖动到新位置,如果我缩小了鼠标,则鼠标比组件更快。放大时,组件的移动速度比鼠标移动的速度快。

如果不缩放,它会一直工作,直到我到达 ScrollPane 自动平移的特定位置。

它必须对确定的节点坐标做一些事情。有谁知道我必须添加什么才能使其正常工作?

我的 Controller 类:

public class MainWindowController implements Initializable {

private final double SCALE_DELTA = 1.1;
private final StackPane zoomPane = new StackPane();
private Group group = new Group();

@FXML
private ScrollPane scrollPane;

@Override
public void initialize(URL url, ResourceBundle rb) {
Node node1 = new Node("Test");
Node node2 = new Node("Test2", 100, 200);

group.getChildren().addAll(node1, node2);
zoomPane.getChildren().add(group);
Group scrollContent = new Group(zoomPane);
scrollPane.setContent(scrollContent);
scrollPane.viewportBoundsProperty().addListener((ObservableValue<? extends Bounds> observable,
Bounds oldValue, Bounds newValue) -> {
zoomPane.setMinSize(newValue.getWidth(), newValue.getHeight());
});

zoomPane.setOnScroll(
(ScrollEvent event) -> {
event.consume();
if (event.getDeltaY() == 0) {
return;
}
double scaleFactor = (event.getDeltaY() > 0) ? SCALE_DELTA : 1 / SCALE_DELTA;
Point2D scrollOffset = figureScrollOffset(scrollContent, scrollPane);
group.setScaleX(group.getScaleX() * scaleFactor);
group.setScaleY(group.getScaleY() * scaleFactor);
repositionScroller(scrollContent, scrollPane, scaleFactor, scrollOffset);
}
);

group.getChildren()
.add(new Node("Test3", 500, 500));

}

private Point2D figureScrollOffset(javafx.scene.Node scrollContent, ScrollPane scroller) {
double extraWidth = scrollContent.getLayoutBounds().getWidth() - scroller.getViewportBounds().getWidth();
double hScrollProportion = (scroller.getHvalue() - scroller.getHmin()) / (scroller.getHmax() - scroller.getHmin());
double scrollXOffset = hScrollProportion * Math.max(0, extraWidth);
double extraHeight = scrollContent.getLayoutBounds().getHeight() - scroller.getViewportBounds().getHeight();
double vScrollProportion = (scroller.getVvalue() - scroller.getVmin()) / (scroller.getVmax() - scroller.getVmin());
double scrollYOffset = vScrollProportion * Math.max(0, extraHeight);
return new Point2D(scrollXOffset, scrollYOffset);
}

private void repositionScroller(javafx.scene.Node scrollContent, ScrollPane scroller, double scaleFactor, Point2D scrollOffset) {
double scrollXOffset = scrollOffset.getX();
double scrollYOffset = scrollOffset.getY();
double extraWidth = scrollContent.getLayoutBounds().getWidth() - scroller.getViewportBounds().getWidth();
if (extraWidth > 0) {
double halfWidth = scroller.getViewportBounds().getWidth() / 2;
double newScrollXOffset = (scaleFactor - 1) * halfWidth + scaleFactor * scrollXOffset;
scroller.setHvalue(scroller.getHmin() + newScrollXOffset * (scroller.getHmax() - scroller.getHmin()) / extraWidth);
} else {
scroller.setHvalue(scroller.getHmin());
}
double extraHeight = scrollContent.getLayoutBounds().getHeight() - scroller.getViewportBounds().getHeight();
if (extraHeight > 0) {
double halfHeight = scroller.getViewportBounds().getHeight() / 2;
double newScrollYOffset = (scaleFactor - 1) * halfHeight + scaleFactor * scrollYOffset;
scroller.setVvalue(scroller.getVmin() + newScrollYOffset * (scroller.getVmax() - scroller.getVmin()) / extraHeight);
} else {
scroller.setHvalue(scroller.getHmin());
}
}
}

节点类:

public class Node extends Parent {

private NodeStatus status = NodeStatus.OK;
private final Image okImage = new Image(getClass().getResourceAsStream("/images/MasterOK.png"));
private ImageView image = new ImageView(okImage);
private final Text label = new Text();
private final Font font = Font.font("Courier", 20);
double orgSceneX, orgSceneY;
double layoutX, layoutY;

public Node(String labelText) {
this(labelText, 0, 0);
}

public Node(String labelText, double x, double y) {
label.setText(labelText);
label.setFont(font);
label.setLayoutX(okImage.getWidth() + 10);
label.setLayoutY(okImage.getHeight() / 2 + 10);
getChildren().add(image);
getChildren().add(label);
setLayoutX(x);
setLayoutY(y);
setCursor(Cursor.MOVE);
setOnMousePressed(new EventHandler<MouseEvent>() {

@Override
public void handle(MouseEvent t) {
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
layoutX = getLayoutX();
layoutY = getLayoutY();
}
});
setOnMouseDragged(new EventHandler<MouseEvent>() {

@Override
public void handle(MouseEvent t) {
setLayoutX(layoutX + t.getSceneX() - orgSceneX);
setLayoutY(layoutY + t.getSceneY() - orgSceneY);
}
});

}

public NodeStatus getStatus() {
return status;
}

public void setStatus(NodeStatus status) {
this.status = status;
}

}

class Delta {

double x, y;
}

和 fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import nodes.*?>

<AnchorPane id="AnchorPane" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cqsmonitor.MainWindowController">
<children>
<Pane layoutX="666.0" layoutY="14.0" prefHeight="572.0" prefWidth="114.0" AnchorPane.bottomAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0">
<children>
<TextField layoutY="30.0" prefHeight="25.0" prefWidth="114.0" />
<Label layoutY="12.0" text="Search:" />
<ChoiceBox layoutY="90.0" prefHeight="25.0" prefWidth="114.0" />
<Label layoutY="73.0" text="View:" />
</children>
</Pane>
<ScrollPane fx:id="scrollPane" layoutX="14.0" layoutY="14.0" pannable="true" prefHeight="571.0" prefWidth="644.0" AnchorPane.bottomAnchor="15.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="142.0" AnchorPane.topAnchor="14.0">
</ScrollPane>
</children>
</AnchorPane>

最佳答案

由于还没有人回答,这里有一些代码。我不想深入研究你的问题并重新发明轮子。

您可以使用鼠标左键拖动来移动节点,使用鼠标滚轮缩放 Pane ,使用鼠标右键平移 Pane 。不需要 ScrollPane。但是,如果您想要 ScrollBars,您可以根据需要随时添加它们。

代码:

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.Node;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

/**
* The canvas which holds all of the nodes of the application.
*/
class PannableCanvas extends Pane {

DoubleProperty myScale = new SimpleDoubleProperty(1.0);

public PannableCanvas() {

setPrefSize(600, 600);
setStyle("-fx-background-color: lightgrey; -fx-border-color: blue;");

// add scale transform
scaleXProperty().bind(myScale);
scaleYProperty().bind(myScale);

// logging
addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
System.out.println(
"canvas event: " + ( ((event.getSceneX() - getBoundsInParent().getMinX()) / getScale()) + ", scale: " + getScale())
);
System.out.println( "canvas bounds: " + getBoundsInParent());
});

}

/**
* Add a grid to the canvas, send it to back
*/
public void addGrid() {

double w = getBoundsInLocal().getWidth();
double h = getBoundsInLocal().getHeight();

// add grid
Canvas grid = new Canvas(w, h);

// don't catch mouse events
grid.setMouseTransparent(true);

GraphicsContext gc = grid.getGraphicsContext2D();

gc.setStroke(Color.GRAY);
gc.setLineWidth(1);

// draw grid lines
double offset = 50;
for( double i=offset; i < w; i+=offset) {
// vertical
gc.strokeLine( i, 0, i, h);
// horizontal
gc.strokeLine( 0, i, w, i);
}

getChildren().add( grid);

grid.toBack();
}

public double getScale() {
return myScale.get();
}

/**
* Set x/y scale
* @param myScale
*/
public void setScale( double scale) {
myScale.set(scale);
}

/**
* Set x/y pivot points
* @param x
* @param y
*/
public void setPivot( double x, double y) {
setTranslateX(getTranslateX()-x);
setTranslateY(getTranslateY()-y);
}
}


/**
* Mouse drag context used for scene and nodes.
*/
class DragContext {

double mouseAnchorX;
double mouseAnchorY;

double translateAnchorX;
double translateAnchorY;

}

/**
* Listeners for making the nodes draggable via left mouse button. Considers if parent is zoomed.
*/
class NodeGestures {

private DragContext nodeDragContext = new DragContext();

PannableCanvas canvas;

public NodeGestures( PannableCanvas canvas) {
this.canvas = canvas;

}

public EventHandler<MouseEvent> getOnMousePressedEventHandler() {
return onMousePressedEventHandler;
}

public EventHandler<MouseEvent> getOnMouseDraggedEventHandler() {
return onMouseDraggedEventHandler;
}

private EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {

public void handle(MouseEvent event) {

// left mouse button => dragging
if( !event.isPrimaryButtonDown())
return;

nodeDragContext.mouseAnchorX = event.getSceneX();
nodeDragContext.mouseAnchorY = event.getSceneY();

Node node = (Node) event.getSource();

nodeDragContext.translateAnchorX = node.getTranslateX();
nodeDragContext.translateAnchorY = node.getTranslateY();

}

};

private EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {

// left mouse button => dragging
if( !event.isPrimaryButtonDown())
return;

double scale = canvas.getScale();

Node node = (Node) event.getSource();

node.setTranslateX(nodeDragContext.translateAnchorX + (( event.getSceneX() - nodeDragContext.mouseAnchorX) / scale));
node.setTranslateY(nodeDragContext.translateAnchorY + (( event.getSceneY() - nodeDragContext.mouseAnchorY) / scale));

event.consume();

}
};
}

/**
* Listeners for making the scene's canvas draggable and zoomable
*/
class SceneGestures {

private static final double MAX_SCALE = 10.0d;
private static final double MIN_SCALE = .1d;

private DragContext sceneDragContext = new DragContext();

PannableCanvas canvas;

public SceneGestures( PannableCanvas canvas) {
this.canvas = canvas;
}

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) {

// right mouse button => panning
if( !event.isSecondaryButtonDown())
return;

sceneDragContext.mouseAnchorX = event.getSceneX();
sceneDragContext.mouseAnchorY = event.getSceneY();

sceneDragContext.translateAnchorX = canvas.getTranslateX();
sceneDragContext.translateAnchorY = canvas.getTranslateY();

}

};

private EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {

// right mouse button => panning
if( !event.isSecondaryButtonDown())
return;

canvas.setTranslateX(sceneDragContext.translateAnchorX + event.getSceneX() - sceneDragContext.mouseAnchorX);
canvas.setTranslateY(sceneDragContext.translateAnchorY + event.getSceneY() - 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 = 1.2;

double scale = canvas.getScale(); // currently we only use Y, same value is used for X
double oldScale = scale;

if (event.getDeltaY() < 0)
scale /= delta;
else
scale *= delta;

scale = clamp( scale, MIN_SCALE, MAX_SCALE);

double f = (scale / oldScale)-1;

double dx = (event.getSceneX() - (canvas.getBoundsInParent().getWidth()/2 + canvas.getBoundsInParent().getMinX()));
double dy = (event.getSceneY() - (canvas.getBoundsInParent().getHeight()/2 + canvas.getBoundsInParent().getMinY()));

canvas.setScale( scale);

// note: pivot value must be untransformed, i. e. without scaling
canvas.setPivot(f*dx, f*dy);

event.consume();

}

};


public static double clamp( double value, double min, double max) {

if( Double.compare(value, min) < 0)
return min;

if( Double.compare(value, max) > 0)
return max;

return value;
}
}



/**
* An application with a zoomable and pannable canvas.
*/
public class ZoomAndScrollApplication extends Application {
public static void main(String[] args) {
launch(args);
}

@Override
public void start(Stage stage) {

Group group = new Group();

// create canvas
PannableCanvas canvas = new PannableCanvas();

// we don't want the canvas on the top/left in this example => just
// translate it a bit
canvas.setTranslateX(100);
canvas.setTranslateY(100);

// create sample nodes which can be dragged
NodeGestures nodeGestures = new NodeGestures( canvas);

Label label1 = new Label("Draggable node 1");
label1.setTranslateX(10);
label1.setTranslateY(10);
label1.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
label1.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

Label label2 = new Label("Draggable node 2");
label2.setTranslateX(100);
label2.setTranslateY(100);
label2.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
label2.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

Label label3 = new Label("Draggable node 3");
label3.setTranslateX(200);
label3.setTranslateY(200);
label3.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
label3.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

Circle circle1 = new Circle( 300, 300, 50);
circle1.setStroke(Color.ORANGE);
circle1.setFill(Color.ORANGE.deriveColor(1, 1, 1, 0.5));
circle1.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
circle1.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

Rectangle rect1 = new Rectangle(100,100);
rect1.setTranslateX(450);
rect1.setTranslateY(450);
rect1.setStroke(Color.BLUE);
rect1.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.5));
rect1.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
rect1.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());

canvas.getChildren().addAll(label1, label2, label3, circle1, rect1);

group.getChildren().add(canvas);

// create scene which can be dragged and zoomed
Scene scene = new Scene(group, 1024, 768);

SceneGestures sceneGestures = new SceneGestures(canvas);
scene.addEventFilter( MouseEvent.MOUSE_PRESSED, sceneGestures.getOnMousePressedEventHandler());
scene.addEventFilter( MouseEvent.MOUSE_DRAGGED, sceneGestures.getOnMouseDraggedEventHandler());
scene.addEventFilter( ScrollEvent.ANY, sceneGestures.getOnScrollEventHandler());

stage.setScene(scene);
stage.show();

canvas.addGrid();

}
}

如果这对您一点帮助都没有,请告诉我,然后我会删除帖子。我对赏金不感兴趣。

关于java - 在可平移/可缩放 Pane 中选取并移动节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32220042/

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