Можно ли сделать ImageView в JavaFX отзывчивым? - PullRequest
0 голосов
/ 20 октября 2019

у меня и некоторых друзей есть проект, в котором мы пытаемся запрограммировать игру на JavaFX. У нас есть GridPane, который растет вместе с ImageViews для хранения карты, игрового персонажа и т. Д. (У игрового персонажа и врагов будет свое собственное изображение, которое мы можем перемещать в сетке). Итак, наша проблема сейчасв том, что мы хотим, чтобы изображения становились больше, когда окно также увеличивается, но сейчас только столбцы GridPane находятся на большем расстоянии друг от друга. Я пытался найти способ изменить это, но я не уверен, если это возможно, потому что ImageViews имеют только «FitHeight» и «FitWidth» и не prefWidth / Height или maxWidth / Height, насколько я вижу. Я также пытался включить HGrow и VGrow всегда или иногда, но это не сработало. Мы не можем изменить их размер, проверяя размер ступеней и постоянно меняя их пропорционально размеру, потому что у нас есть более 800 изображений в нашей карте для отображения всех изображений. Вот мой код:

         </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 Ответ

0 голосов
/ 23 октября 2019

Одним из решений является создание Region подкласса, который просто оборачивает ImageView. Это лучше, чем привязка свойств подгонки ширины / высоты ImageView к его родительскому элементу, поскольку привязка дочерних измерений к родительским измерениям может вызвать проблемы с системой макетов.

Вот пример:

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

Вы можете установить свойства minWidth, minHeight, maxWidth и maxHeight, чтобы контролировать, насколько маленьким или большим может быть изображение.


Вы можете сделать почти то же самое, используя 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));

. Это приведет к заполнению всего изображения Region, как если бы preserveRatio было установлено на false в примере ResizableImageView. Если вы хотите, чтобы он вел себя так, как если бы preserveRatio был установлен на true, используйте следующее BackgroundSize:

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

Разница в пятом аргументе contain, который был изменен сfalse до true. Ознакомьтесь с документацией , чтобы лучше понять, что делает каждый аргумент.

Обратите внимание, что использование BackgroundImage таким образом означает, что Region не будет вычислять свои предпочтительные измерения на основеобраз. Это может или не может вызвать проблемы для вас. Например, при первоначальном изменении размера макета он не будет учитывать изображение. Однако после этого все должно работать так же, как ResizableImageView - так как Region изменяется, как и изображение.

A BackgroundImage также можно установить с помощью 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 */
}
...