我想制作一个内置自定义Pane的ScrollPane,它有两个Child。一个拿着我的物品,另一个拿着背景。我想这样做,如果我缩小,并且内容小于视口,那么内容的大小将扩展,填充视口中的新位置。如果我缩小它然后它将保持不变,我现在有更大的内容区域。内容的新宽度为:originalWidth + viewportWidth - scaledWidth。
我已经制作了网格和缩放工作,但我无法制作它以便调整内容的大小。我曾尝试在缩放到当前视口大小时设置内容大小,但它不起作用。
布局在fxml中定义。除了ScrollPane内容设置填充高度和宽度之外,没什么不同寻常的。
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);
}
}
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());
});
}
}
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);
}
}
答案 0 :(得分:0)
我不确定我是否理解了你想要实现的目标。但是如果你的目标是让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);
}
}