我想制作一个 ScrollPane,里面有一个自定义 Pane ,它有两个子项。一张用来放置我的元素,另一张仅用于背景。我想做到这一点,如果我缩小,并且内容小于视口(viewport),那么内容的大小会扩大,填充视口(viewport)中的新位置。如果我放大回来,它会保持不变,并且我现在在区域中拥有更大的内容。内容的新宽度将为:originalWidth + viewportWidth -scaledWidth。
我已经制作了网格,并且缩放可以工作,但我无法制作它来调整内容的大小。我尝试在缩放到当前视口(viewport)大小时设置内容大小,但它不起作用。
问题:
- 我做错了什么?
布局在 fxml 中定义。另一个比ScrollPane内容设置为填充高度和宽度没有什么不寻常的。
自定义 Pane 类:
public class CustomPane extends StackPane implements Initializable {
@FXML
StackPane view;
@FXML
AnchorPane objectPane;
@FXML
GriddedPane background;
private DoubleProperty zoomFactor = new SimpleDoubleProperty(1.5);
private BooleanProperty altStatus = new SimpleBooleanProperty(false);
public CustomPane() {
super();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getClassLoader().getResource("CustomCanvas.fxml"));
loader.setController(this);
loader.setRoot(this);
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void initialize(URL location, ResourceBundle resources) {
objectPane.setStyle("-fx-background-color: transparent");
objectPane.prefWidthProperty().bind(prefWidthProperty());
objectPane.prefHeightProperty().bind(prefHeightProperty());
objectPane.getChildren().add(new Circle(512, 378, 20, Color.RED));
}
public void zoom(ScrollPane parent, Node node, double factor, double x, double y) {
Timeline timeline = new Timeline(60);
// determine scale
double oldScale = node.getScaleX();
double scale = oldScale * factor;
double f = (scale / oldScale) - 1;
// determine offset that we will have to move the node
Bounds bounds = node.localToScene(node.getBoundsInLocal());
double dx = (x - (bounds.getWidth() / 2 + bounds.getMinX()));
double dy = (y - (bounds.getHeight() / 2 + bounds.getMinY()));
// timeline that scales and moves the node
timeline.getKeyFrames().clear();
timeline.getKeyFrames().addAll(
new KeyFrame(Duration.millis(100), new KeyValue(node.translateXProperty(), node.getTranslateX() - f * dx)),
new KeyFrame(Duration.millis(100), new KeyValue(node.translateYProperty(), node.getTranslateY() - f * dy)),
new KeyFrame(Duration.millis(100), new KeyValue(node.scaleXProperty(), scale)),
new KeyFrame(Duration.millis(100), new KeyValue(node.scaleYProperty(), scale))
);
timeline.play();
Bounds viewportBounds = parent.getViewportBounds();
if (bounds.getWidth() < viewportBounds.getWidth()) {
setMinWidth(viewportBounds.getWidth());
requestLayout();
}
if (getMinHeight() < viewportBounds.getHeight()) {
setMinHeight(viewportBounds.getHeight());
requestLayout();
}
}
public final Double getZoomFactor() {
return zoomFactor.get();
}
public final void setZoomFactor(Double zoomFactor) {
this.zoomFactor.set(zoomFactor);
}
public final DoubleProperty zoomFactorProperty() {
return zoomFactor;
}
public boolean getAltStatus() {
return altStatus.get();
}
public BooleanProperty altStatusProperty() {
return altStatus;
}
public void setAltStatus(boolean altStatus) {
this.altStatus.set(altStatus);
}
}
Controller 类:
public class Controller implements Initializable {
public ScrollPane scrollPane;
public CustomPane customPane;
public AnchorPane anchorPane;
public Tab tab1;
@Override
public void initialize(URL location, ResourceBundle resources) {
scrollPane.viewportBoundsProperty().addListener((observable, oldValue, newValue) -> {
customPane.setMinSize(newValue.getWidth(), newValue.getHeight());
});
scrollPane.requestLayout();
tab1.getTabPane().addEventFilter(KeyEvent.KEY_PRESSED, event1 -> {
if (event1.getCode() == KeyCode.ALT)
customPane.setAltStatus(true);
});
tab1.getTabPane().addEventFilter(KeyEvent.KEY_RELEASED, event1 -> {
if (event1.getCode() == KeyCode.ALT)
customPane.setAltStatus(false);
});
scrollPane.setOnScroll(event -> {
double zoomFactor = 1.5;
if (event.getDeltaY() <= 0)
zoomFactor = 1 / zoomFactor;
customPane.setZoomFactor(zoomFactor);
if (customPane.getAltStatus())
customPane.zoom(scrollPane, customPane, customPane.getZoomFactor(), event.getSceneX(), event.getSceneY());
});
}
}
GriddedPane 类:
public class GriddedPane extends Pane implements Initializable {
DoubleProperty gridWidth = new SimpleDoubleProperty(this, "gridWidth", 10);
DoubleProperty gridHeight = new SimpleDoubleProperty(this, "gridHeight", 10);
public GriddedPane() {
super();
}
@Override
public void initialize(URL location, ResourceBundle resources) {
}
@Override
protected void layoutChildren() {
getChildren().clear();
setMouseTransparent(true);
toBack();
for (int i = 0; i < getHeight(); i += getGridWidth())
getChildren().add(makeLine(0, i, getWidth(), i, "x"));
for (int i = 0; i < getWidth(); i += getGridHeight())
getChildren().add(makeLine(i, 0, i, getHeight(), "y"));
}
public void redrawLines() {
for (Node n : getChildren()) {
Line l = (Line) n;
if (l.getUserData().equals("x")) {
l.setEndX(getWidth());
} else if (l.getUserData().equals("y")) {
l.setEndY(getHeight());
}
}
}
private Line makeLine(double sx, double sy, double ex, double ey, String data) {
final Line line = new Line(sx, sy, ex, ey);
if (ex % (getGridWidth() * 10) == 0.0) {
line.setStroke(Color.BLACK);
line.setStrokeWidth(0.3);
} else if (ey % (getGridHeight() * 10) == 0.0) {
line.setStroke(Color.BLACK);
line.setStrokeWidth(0.3);
} else {
line.setStroke(Color.GRAY);
line.setStrokeWidth(0.1);
}
line.setUserData(data);
return line;
}
public double getGridWidth() {
return gridWidth.get();
}
public DoubleProperty gridWidthProperty() {
return gridWidth;
}
public void setGridWidth(double gridWidth) {
this.gridWidth.set(gridWidth);
}
public double getGridHeight() {
return gridHeight.get();
}
public DoubleProperty gridHeightProperty() {
return gridHeight;
}
public void setGridHeight(double gridHeight) {
this.gridHeight.set(gridHeight);
}
}
最佳答案
不太确定我是否理解您想要实现的目标。但是,如果您的目标是使scrollPane的内容永远不会小于scrollPane的宽度,那么这对我来说是有效的:
public class Zoom extends Application {
@Override
public void start(Stage primaryStage) {
ImageView imageView = new ImageView(new Image(someImage));
ScrollPane scrollPane = new ScrollPane(imageView);
StackPane root = new StackPane(scrollPane);
imageView.fitWidthProperty().bind(scrollPane.widthProperty());
imageView.fitHeightProperty().bind(scrollPane.heightProperty());
scrollPane.setOnScroll(evt -> {
boolean zoomOut = evt.getDeltaY() < 0;
double zoomFactor = zoomOut ? -0.2 : 0.2;
imageView.setScaleX(imageView.getScaleX() + zoomFactor);
imageView.setScaleY(imageView.getScaleY() + zoomFactor);
if (zoomOut) {
Bounds bounds = imageView.getBoundsInParent();
if (bounds.getWidth() < scrollPane.getWidth()) {
imageView.setScaleX(1);
imageView.setScaleY(1);
}
}
});
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
关于java - 如果小于视口(viewport),则扩展滚动 Pane 的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36669769/