JavaFX 调整 BorderPane 中心的 ImageView 大小

问题描述 投票:0回答:1

我在 BorderPane 的中心有一个 ImageView。左右是两个按钮。 BorderPnae 位于分割窗格内。我将 ImageView 的大小绑定到 BorderPane,如下所示:

imageView.fitHeightProperty().bind(borderPane.heightProperty());
imageView.fitWidthProperty().bind(borderPane.widthProperty());
imageView.setManaged(false);

当 setManaged 为 false 时,它会调整大小,但图像不在中心。如果我删除这条线,图像的中心就会很好。 这是一个mwe:

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {

            SplitPane root = new SplitPane();
            BorderPane borderPane = new BorderPane();
            ImageView imageView = new ImageView();
            VBox placeHolder = new VBox();
            
            imageView.fitHeightProperty().bind(borderPane.heightProperty());
            imageView.fitWidthProperty().bind(borderPane.widthProperty());
            imageView.setManaged(false);
            
            borderPane.setCenter(imageView);
            imageView.setImage(new Image("pathToImage"));
            root.getItems().addAll(borderPane,placeHolder);
            Scene scene = new Scene(root,700,700);          
            primaryStage.setScene(scene);
            
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}

enter image description here

我正在寻找一种将两者存档的方法。我尝试使用 Hbox 作为按钮和图像视图的容器,但这也禁用了大小调整。

java javafx
1个回答
0
投票

将节点的尺寸绑定到其父级的尺寸通常会导致布局期间出现问题。更具体地说,它往往会阻止父级正确调整大小。创建“可调整大小的图像视图”的最可靠方法是创建自定义布局并覆盖

layoutChildren()
以调整图像视图的大小。

这是一个非常简单的例子:

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Region;

public class ImageRegion extends Region {

  private final ObjectProperty<Image> image = new SimpleObjectProperty<>(this, "image") {
    @Override protected void invalidated() { view.setImage(get()); }
  };
  public final void setImage(Image image) { this.image.set(image); }
  public final Image getImage() { return image.get(); }
  public final ObjectProperty<Image> imageProperty() { return image; }

  private final ImageView view = new ImageView();

  public ImageRegion() {
    getStyleClass().add("image-region");

    view.setPreserveRatio(true);
    getChildren().add(view);
  }

  public ImageRegion(Image image) {
    this();
    setImage(image);
  }

  public ImageRegion(String imageUrl) {
    this(new Image(imageUrl));
  }

  @Override
  protected void layoutChildren() {
    if (getImage() == null) {
      return;
    }

    // content area dimensions
    double cx = getInsets().getLeft();
    double cy = getInsets().getTop();
    double cw = getWidth() - getInsets().getRight() - cx;
    double ch = getHeight() - getInsets().getBottom() - cy;

    // image dimensions
    double iw = getImageWidth();
    double ih = getImageHeight();

    view.setFitWidth(cw < iw ? cw : 0);
    view.setFitHeight(ch < ih ? ch : 0);

    positionInArea(view, cx, cy, cw, ch, 0, HPos.CENTER, VPos.CENTER);
  }

  /*
   * Ignore the Image and ImageView when computing the minimum width and
   * height. This allows the ImageRegion to be sized smaller than the Image.
   * 
   * Compute the preferred width and height based on the Image directly rather 
   * than the ImageView.
   * 
   * The Region.computeMaxWidth and Region.computeMaxHeight methods both
   * return Double.MAX_VALUE. We want the ImageRegion able to be sized
   * larger than the Image, so there is no reason to override those methods.
   */

  @Override
  protected double computeMinWidth(double height) {
    return getInsets().getLeft() + getInsets().getRight();
  }

  @Override
  protected double computeMinHeight(double width) {
    return getInsets().getTop() - getInsets().getBottom();
  }

  @Override
  protected double computePrefWidth(double height) {
    return getInsets().getLeft() + getInsets().getRight() + getImageWidth();
  }

  @Override
  protected double computePrefHeight(double width) {
    return getInsets().getTop() + getInsets().getBottom() + getImageHeight();
  }

  private double getImageWidth() {
    var image = getImage();
    return image == null ? 0 : image.getWidth();
  }

  private double getImageHeight() {
    var image = getImage();
    return image == null ? 0 : image.getHeight();
  }
}

注意这个

ImageRegion
课程:

  • 将保留图像的纵横比。

  • 如果区域的内容区域小于图像,将使图像变小。

  • 如果区域的内容区域大于图像,
  • 不会使图像变大。

如果需要,您可以修改

layoutChildren()

 逻辑以更好地适合您的用例。

对上述类的一些可能的改进包括:

  • 添加

    preserveRatio

    属性来控制是否保留图像的宽高比。

  • 添加

    alignment

     属性,用于控制图像小于内容区域时的定位方式。

  • 创建不同“拟合策略”的枚举并添加关联属性。一些不同的策略可能是:“无”、“适合宽度”、“适合高度”、“适合两者”等。

  • 使前三点中提到的属性可通过 CSS 设置样式。

  • 计算 fit-width 和 fit-height 时使用

    snapXXX

     方法。

© www.soinside.com 2019 - 2024. All rights reserved.