是否可以使JavaFX中的ImageView响应? [英] Is it possible to make a ImageView in JavaFX responsive?

查看:106
本文介绍了是否可以使JavaFX中的ImageView响应?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我和一些朋友有一个项目,我们尝试在JavaFX中编写游戏。我们有一个GridPane,里面长有ImageViews来容纳地图和游戏角色等。(游戏角色和敌人将拥有自己的imageview,我们可以在网格窗格中四处移动。)也就是说,当窗口也变大时,我们希望图片变大,但是现在只有GridPane的列之间的距离越来越大。我试图找到一种方法来更改此设置,但是据我所知,我不确定是否可以使ImageViews仅具有 FitHeight和 FitWidth,而没有prefWidth / Height或maxWidth / Height。我还尝试将HGrow和VGrow始终或有时置于打开状态,但是没有用。我们无法通过检查舞台大小并始终按比例更改它们的大小来调整它们的大小,因为我们的地图中有800多个ImageView可以显示所有图像。
这是我的代码:

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


解决方案

一种解决方案是创建 Region 子类,只包装 ImageView 。这比将 ImageView 的fit width / height属性与其父级绑定更好,因为将子级的尺寸绑定到其父级的尺寸可能会导致布局系统出现问题。



这里是一个例子:

 导入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)
公共类ResizableImageView扩展了区域{

/ * *************** ****************************************************** ****
* *
*属性*
* *
*********************** **************************************************** /

//-图片属性

私有最终ObjectProperty< Image>图像=
新的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();
}

公共最终ObjectProperty< Image> imageProperty(){
返回图片;
}

// --preserveRatio属性

私有最终BooleanProperty prepareRatio =
new SimpleBooleanProperty(this, preserveRatio){
@Override
protected void invalidated(){
imageView.setPreserveRatio(get());
}
};

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

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

public final BooleanProperty prepareRatioProperty(){
return reserveRatio;
}

/ * *********************************** **************************************
* *
*实例字段*
* *
****************************************** ********************************* /

私人最终ImageView imageView = new ImageView();

/ * **************************************** ********************************
* *
*构造函数*
* *
************************************************ *********************** /

public ResizableImageView(){
getStyleClass()。add( resizable-图片视图);
getChildren()。add(imageView);
}

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

/ * *********************************** **************************************
* *
*方法*
* *
******************************************* ******************************** /

@Override
受保护的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 requestWidth = image.getRequestedWidth();
prefWidth + =(requestedWidth> 0.0?requestWidth:image.getWidth());
}

return snapSizeX(prefWidth);
}

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

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

return snapSizeY(prefHeight);
}
}

您可以设置 minWidth minHeight maxWidth maxHeight 属性可控制图片的大小。






您可以使用来完成几乎相同的操作一个 BackgroundImage

  var 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 ,就像在 ResizableImageView preserveRatio 设置为 false 一样c $ c>示例。如果您希望它的行为就像 preserveRatio 设置为 true 一样,请使用以下 BackgroundSize

  new BackgroundSize(1.0,1.0,true,true,真假); 

差异是第五个参数,包含 ,已从 false 更改为 true 。查看文档以了解更多信息每个参数的作用。



请注意,以这种方式使用 BackgroundImage 表示 Region 不会基于图像计算其首选尺寸。这可能会或可能不会给您造成问题。例如,在布局的初始大小调整过程中,不会考虑图像。但是,此后,所有内容应与 ResizableImageView 一样工作-因为调整了 Region 的大小,因此图像也是如此。



A BackgroundImage 也可以通过CSS设置:

  .your-region-class {
-fx-background-image:url(...);
-fx-background-repeat:不重复;
-fx-background-position:中心;
-fx-background-size:包含; / *或100%100%的行为就好像keepRatio为false * /
}


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>

解决方案

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 */
}

这篇关于是否可以使JavaFX中的ImageView响应?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆