如果小于视口,则扩展Scrollpane的内容

时间:2016-04-16 21:08:54

标签: java javafx

我想制作一个内置自定义Pane的ScrollPane,它有两个Child。一个拿着我的物品,另一个拿着背景。我想这样做,如果我缩小,并且内容小于视口,那么内容的大小将扩展,填充视口中的新位置。如果我缩小它然后它将保持不变,我现在有更大的内容区域。内容的新宽度为:originalWidth + viewportWidth - scaledWidth。

我已经制作了网格和缩放工作,但我无法制作它以便调整内容的大小。我曾尝试在缩放到当前视口大小时设置内容大小,但它不起作用。

问题:

  • 我做错了什么?

布局在fxml中定义。除了ScrollPane内容设置填充高度和宽度之外,没什么不同寻常的。

CustomPane类:

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

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

1 个答案:

答案 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);
    }
}