JavaFX调整子级相对于父级的大小 [英] JavaFX resize children relative to parent

查看:120
本文介绍了JavaFX调整子级相对于父级的大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一个可调整大小的窗格中,该窗格显示一个imageView,我想选择多个矩形.

Within a resizable Pane that shows an imageView i'd like to select multiple rectangles.

为此,我创建了一个类SelectableImageViewPane.这两个类 ImageViewPane

To do so I created a class SelectableImageViewPane. The two classes ImageViewPane and RubberBandSelection are from the com.bitplan.javafx Project where I am a committer.

调整窗口大小时,相关窗格的大小也进行了调整,如您从例如的生成的调试输出中看到的那样. SelectableImageViewPaneDemo 和以下示例屏幕截图.不幸的是,选择矩形未调整大小/位置.

When the window is resized the relevant panes are resized nicely as you can see from the debug output produced by e.g. SelectableImageViewPaneDemo and the following example screenshots. Unfortunately the selection rectangles are not resized / repositioned.

我如何确保子矩形-相对于周围的玻璃窗格调整大小/位置并与ImageViewPane/ImageView同步?

package com.bitplan.javafx;

import java.util.logging.Level;
import java.util.logging.Logger;

import javafx.geometry.Bounds;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;

/**
 * an ImageViewPane with a RubberBandSelection that properly resizes the rectangles
 * @author wf
 *
 */
public class SelectableImageViewPane extends StackPane {
  protected static Logger LOGGER = Logger.getLogger("com.bitplan.javafx");
  public static boolean debug=true;
  private RubberBandSelection selection;
  private ImageViewPane imageViewPane;
  private Pane glassPane;

  /**
   * get my selection
   * @return
   */
  public RubberBandSelection getSelection() {
    return selection;
  }

  /**
   * show the bound of the given node with the given title
   * @param title
   * @param n
   */
  public void showBounds(String title,Node n) {
    if (debug) {
      Bounds b = n.getLayoutBounds();
      LOGGER.log(Level.INFO,String.format("%s: min %.0f,%.0f max %.0f,%.0f",title,b.getMinX(),b.getMinY(),b.getMaxX(),b.getMaxY()));        
    }
  }

  @Override
  protected void layoutChildren() {
    super.layoutChildren();
    int index=1;
    if (debug) {
      showBounds("pane",this);
      showBounds("imageViewPane",imageViewPane);
      showBounds("glassPane",glassPane);
      showBounds("imageView",imageViewPane.imageViewProperty().get());
    }
    for (Node n:selection.selected) {
     showBounds(""+(index++),n);
    }
  }

  /**
   * create me
   * @param imageView
   */
  public SelectableImageViewPane(ImageView imageView) {
    imageViewPane=new ImageViewPane(imageView);
    getChildren().add(imageViewPane);
    StackPane.setAlignment(imageViewPane, Pos.CENTER);
    glassPane = new AnchorPane();
    glassPane.setStyle("-fx-background-color: rgba(0, 0, 0, 0.1);");
    getChildren().add(glassPane);
    //glassPane.prefWidthProperty().bind(imageViewPane.widthProperty());
    //glassPane.prefHeightProperty().bind(imageViewPane.heightProperty());
    selection = new RubberBandSelection(glassPane);
    selection.setSelectButton(true);
  }

}

更新 同时,我修改了RubberBandSelection 以记住矩形的相对边界在父对象中(无论如何,以后在我的应用程序中使用矩形时都需要使用它).如果父级的尺寸发生更改,此信息可用于在父级中正确布局矩形.

Update In the meantime I modified RubberBandSelection to remember the relative bounds of the rectangles within the parent (which I'll need later anyway when using the rectangles in my application). This information can be used to properly layout the rectangles in the parent should the parent's dimension change.

Bounds rB = s.relativeBounds;
                double w = getWidth();
                double h=getHeight();
                double minX=rB.getMinX()*w;
                double minY=rB.getMinY()*h;
                double width=rB.getWidth()*w;
                double height=rB.getHeight()*h;
                layoutInArea(s.node, minX,minY,width,height, 0, HPos.LEFT,
                          VPos.TOP);

该解决方案效果更好,但仍然存在一些涉及父级中x/y偏移量的问题.

The solution works better but there is still some issue probably involving the x/y offset within the parent.

更新了SelectableImageViewPane

package com.bitplan.javafx;

import java.util.logging.Level;
import java.util.logging.Logger;

import com.bitplan.javafx.RubberBandSelection.Selection;

import javafx.geometry.Bounds;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;

/**
 * an ImageViewPane with a RubberBandSelection that properly resizes the
 * rectangles
 * 
 * @author wf
 *
 */
public class SelectableImageViewPane extends StackPane {
    protected static Logger LOGGER = Logger.getLogger("com.bitplan.javafx");
    public static boolean debug = true;
    private RubberBandSelection selection;
    private ImageViewPane imageViewPane;
    private Pane glassPane;

    /**
     * get my selection
     * 
     * @return
     */
    public RubberBandSelection getSelection() {
        return selection;
    }

    /**
     * show the bound of the given node with the given title
     * 
     * @param title
     * @param n
     */
    public void showBounds(String title, Node n) {
        if (debug) {
            Bounds b = n.getLayoutBounds();
            LOGGER.log(Level.INFO, String.format("%s: min %.0f,%.0f max %.0f,%.0f", title, b.getMinX(), b.getMinY(),
                    b.getMaxX(), b.getMaxY()));
        }
    }

    @Override
    protected void layoutChildren() {
        super.layoutChildren();
        int index = 1;
        if (debug) {
            showBounds("pane", this);
            showBounds("imageViewPane", imageViewPane);
            showBounds("glassPane", glassPane);
            showBounds("imageView", imageViewPane.imageViewProperty().get());
        }
        for (Selection s : selection.selected.values()) {

            if (debug) {
                showBounds("" + (index++), s.node);
                LOGGER.log(Level.INFO, s.asPercent());
            }
            Bounds rB = s.relativeBounds;
            double w = getWidth();
            double h=getHeight();
            double minX=rB.getMinX()*w;
            double minY=rB.getMinY()*h;
            double width=rB.getWidth()*w;
            double height=rB.getHeight()*h;
            layoutInArea(s.node, minX,minY,width,height, 0, HPos.LEFT,
                      VPos.TOP);
        }
    }

    /**
     * create me
     * 
     * @param imageView
     */
    public SelectableImageViewPane(ImageView imageView) {
        imageViewPane = new ImageViewPane(imageView);
        getChildren().add(imageViewPane);
        StackPane.setAlignment(imageViewPane, Pos.CENTER);
        glassPane = new AnchorPane();
        glassPane.setStyle("-fx-background-color: rgba(0, 0, 0, 0.1);");
        getChildren().add(glassPane);
        // glassPane.prefWidthProperty().bind(imageViewPane.widthProperty());
        // glassPane.prefHeightProperty().bind(imageViewPane.heightProperty());
        selection = new RubberBandSelection(glassPane);
        selection.setSelectButton(true);
    }

}

推荐答案

有两种主要的方法可以使这项工作:

There are two main ingredients to make this working:

  1. 跟踪图像的大小-我修改了
  1. Tracking the size of the image - I modified ImageViewPane accordingly.
  2. making sure the selected rectangles within the image are resized in sync with changes of the Image. The RelativePane below is a helper class in which the rectangles (buttons in fact) can be positioned relatively.

请注意,chriscamacho对原始代码进行了两项更改:

Please note that there are two changes to the original code by chriscamacho:

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