Within a resizable Pane that shows an imageView i'd like to select multiple rectangles.
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.
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.
How could i make sure the child - rectangles are resized/repositioned relative to the surrounding glasspane and in sync with the 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);
}
}
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);
The solution works better but there is still some issue probably involving the x/y offset within the parent.
Updated 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);
}
}