I am using Scene Builder to create my scenes, I have added cards (ImageViews) to the VBoxes and all 12 cards don't seem to nicely fit, although they do fit in the HBoxes that I have. I couldn't find any property that lets me reduce the spacing between Nodes inside my VBox. I have shown a picture of how my VBox looks and there is also a picture of my HBox (thats how I want it to look). If that's not possible then I want to be able to overlap the images so they do fit.
Asked
Active
Viewed 741 times
0
-
Either your VBox has a spacing property set to a non-zero value or your images have a little transparent region on the top. Can you please check? – ItachiUchiha Feb 24 '18 at 03:33
-
actually originally the images were being added straight like they are in the HBox, so I rotated the images so they face the center which caused the extra space. Either way, I wasn't able to show 12 images like the HBox shows them. – Feb 24 '18 at 03:50
-
You can make use of the [viewportProperty](https://docs.oracle.com/javase/9/docs/api/javafx/scene/image/ImageView.html#viewportProperty--) to define specific area to use from your ImageView. – ItachiUchiha Feb 24 '18 at 05:36
1 Answers
0
This is not supported by VBox
(At least there is no way I know of that would).
You could however override layoutChildren
to move up the nodes, if the content does not fit and override computeMinHeight
to return the maximum of the minHeight values:
public class OverlappingVBox extends VBox {
@Override
protected void layoutChildren() {
super.layoutChildren();
List<Node> managed = getManagedChildren();
int count = managed.size();
if (count == 0) {
return;
}
double contentAreaMaxY = getHeight() - getInsets().getBottom();
Node lastNode = managed.get(managed.size() - 1);
double maxY = lastNode.getLayoutY() + lastNode.getLayoutBounds().getMaxY();
if (contentAreaMaxY < maxY) {
// reduce layoutY if content does not fit
double gap = (contentAreaMaxY - maxY) / (count - 1);
for (int i = 1; i < count; i++) {
Node n = managed.get(i);
n.setLayoutY(n.getLayoutY() + i * gap);
}
}
}
@Override
protected double computeMinHeight(double width) {
// min height = max min height
double result = 0;
Insets insets = getInsets();
double contentWidth = width - insets.getLeft() - insets.getRight();
for (Node n : getManagedChildren()) {
double mH = n.minHeight(contentWidth);
if (mH > result) {
result = mH;
}
}
return result + insets.getTop() + insets.getBottom();
}
}
Usage example
@Override
public void start(Stage primaryStage) {
OverlappingVBox root = new OverlappingVBox();
Color c = Color.WHITE;
for (int i = 0; i < 10; i++) {
root.getChildren().add(new Rectangle(50, 50, c));
c = c.invert();
}
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

fabian
- 80,457
- 12
- 86
- 114
-
how would I use this keeping in mind that I used the scene builder to create my Vbox, which is inside a BoarderPane. Can I create an OverlappingVbox object and set it to my Vbox through casting? – Feb 24 '18 at 01:32
-
You should be able to use `OverlappingVBox` instead of `VBox` by replacing `
` elements with ` – fabian Feb 24 '18 at 01:53` elements (be sure the appropriate `` processing instruction is added). Since `OverlappingVBox` extends `VBox` an assignment of a `OverlappingVBox` to a `VBox` field works fine. `FXMLLoader` also has no difficulties to inject the node to a field... You could also add the layout to scenebuilder, see https://stackoverflow.com/questions/30063792/adding-a-custom-component-to-scenebuilder-2-0 -
this solves most of my problem, but the 1st card is still not visible (half covered) while there is still space at the bottom – Feb 24 '18 at 09:02
-
@ScrappyMontana Whoops, there was a typo `maxY` needs to be calculated `maxY` not `maxX` of course... – fabian Feb 24 '18 at 10:00