Is it possible to make a ImageView in JavaFX responsive?

♀尐吖头ヾ 提交于 2020-01-25 06:48:27

问题


me and some friends are having a project, where we try to programm a game in JavaFX. We´ve got a GridPane, thats growing with ImageViews inside to hold the map and the game character, etc. (The game character and enemies will have their own imageview, that we can move around in the gridpane.) So, our problem now is, that we want out pictures to get bigger, when the window is getting bigger also, but right now only the columns of the GridPane are getting more distance to each other. I tried to find a way to change that, but I am not sure, if it is possible, cause ImageViews only have "FitHeight" and "FitWidth" and no prefWidth/Height or maxWidth/Height, as far as I see. I also tried to put HGrow and VGrow on always or sometimes, but it didn´t work. We can´t resize them with checking the stages size and changing their size in proportion to it all the time, cause we´ve got more than 800 ImageViews in our map to display all the Images. Here´s my code:

         </image></ImageView>
  <ImageView id="sample" fitHeight="25.0" fitWidth="27.0" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="15" GridPane.hgrow="ALWAYS" GridPane.rowIndex="24" GridPane.vgrow="ALWAYS">
         <image>
            <Image url="@sample.png" />
         </image></ImageView>

回答1:


One solution is to create a Region subclass that simply wraps an ImageView. This is better than binding the ImageView's fit width/height properties to its parent because binding a child's dimensions to its parent's dimensions can cause issues with the layout system.

Here's an example:

import javafx.beans.DefaultProperty;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
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;

@DefaultProperty("image")
public class ResizableImageView extends Region {

  /* *********************************************************************
   *                                                                     *
   * Properties                                                          *
   *                                                                     *
   ***********************************************************************/

  // -- image property

  private final ObjectProperty<Image> image =
      new SimpleObjectProperty<>(this, "image") {
        @Override
        protected void invalidated() {
          imageView.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;
  }

  // -- preserveRatio property

  private final BooleanProperty preserveRatio =
      new SimpleBooleanProperty(this, "preserveRatio") {
        @Override
        protected void invalidated() {
          imageView.setPreserveRatio(get());
        }
      };

  public final void setPreserveRatio(boolean preserveRatio) {
    this.preserveRatio.set(preserveRatio);
  }

  public final boolean isPreserveRatio() {
    return preserveRatio.get();
  }

  public final BooleanProperty preserveRatioProperty() {
    return preserveRatio;
  }

  /* *********************************************************************
   *                                                                     *
   * Instance Fields                                                     *
   *                                                                     *
   ***********************************************************************/

  private final ImageView imageView = new ImageView();

  /* *********************************************************************
   *                                                                     *
   * Constructors                                                        *
   *                                                                     *
   ***********************************************************************/

  public ResizableImageView() {
    getStyleClass().add("resizable-image-view");
    getChildren().add(imageView);
  }

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

  /* *********************************************************************
   *                                                                     *
   * Methods                                                             *
   *                                                                     *
   ***********************************************************************/

  @Override
  protected void layoutChildren() {
    double x = snappedLeftInset();
    double y = snappedTopInset();
    double w = getWidth() - x - snappedRightInset();
    double h = getHeight() - y - snappedRightInset();

    imageView.setFitWidth(w);
    imageView.setFitHeight(h);
    positionInArea(imageView, x, y, w, h, -1, HPos.CENTER, VPos.CENTER);
  }

  @Override
  protected double computePrefWidth(double height) {
    double prefWidth = snappedLeftInset() + snappedRightInset();

    var image = getImage();
    if (image != null) {
      double requestedWidth = image.getRequestedWidth();
      prefWidth += (requestedWidth > 0.0 ? requestedWidth : image.getWidth());
    }

    return snapSizeX(prefWidth);
  }

  @Override
  protected double computePrefHeight(double width) {
    double prefHeight = snappedTopInset() + snappedBottomInset();

    var image = getImage();
    if (image != null) {
      double requestedHeight = image.getRequestedHeight();
      prefHeight += (requestedHeight > 0.0 ? requestedHeight : image.getHeight());
    }

    return snapSizeY(prefHeight);
  }
}

You can set the minWidth, minHeight, maxWidth, and maxHeight properties to control how small or large the image can get.


You can accomplish nearly the same thing by using a BackgroundImage.

var image = new Image(...);
var bgImage = new BackgroundImage(
    image,
    BackgroundRepeat.NO_REPEAT,
    BackgroundRepeat.NO_REPEAT,
    BackgroundPosition.CENTER,
    new BackgroundSize(1.0, 1.0, true, true, false, false)
);

var region = new Region();
region.setBackground(new Background(bgImage));

This will cause the image to fill the entire Region, same as if preserveRatio was set to false in the a ResizableImageView example. If you want this to behave as if preserveRatio was set to true then use the following BackgroundSize:

new BackgroundSize(1.0, 1.0, true, true, true, false);

The difference is the fifth argument, contain, which has been changed from false to true. Check out the documentation to understand more about what each argument does.

Note that using a BackgroundImage in this way means the Region won't compute its preferred dimensions based on the image. This may or may not cause problems for you. For instance, during a layout's initial sizing it won't take the image into account. However, afterwards everything should work the same as ResizableImageView—as the Region is resized so is the image.

A BackgroundImage can also be set via CSS:

.your-region-class {
    -fx-background-image: url(...);
    -fx-background-repeat: no-repeat;
    -fx-background-position: center;
    -fx-background-size: contain; /* or 100% 100% to act as if preserveRatio is false */
}


来源:https://stackoverflow.com/questions/58476162/is-it-possible-to-make-a-imageview-in-javafx-responsive

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!