【发布时间】:2015-11-20 02:30:22
【问题描述】:
我试图在ScrollPane 中放置一些组件。这些组件应该能够通过鼠标(单击并拖动)在此窗格中移动。 ScrollPane 本身是可平移和可缩放的。
现在,如果我选择其中一个并将其拖动到新位置,如果我缩小了鼠标,则鼠标比组件快。放大时,组件的移动速度比鼠标移动快。
如果不缩放,它会一直工作,直到我到达 ScrollPane 自动平移的某个位置。
它必须对节点的确定坐标做一些事情。有谁知道我必须添加什么才能使其正常工作?
我的控制器类:
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>
【问题讨论】: