Mindstorm38
Mindstorm38

Reputation: 17

JavaFX children influence parent's width

I've a HBox with two children (an ImageView and a Text), but under certain conditions i want to hide the text to force HBox to reduce its with. I already have a technic that consists to bind managedProperty to visibleProperty, but it not work as expected because the text force the HBox width to include the text width.

My question is : How can i disable a node collision (on his parent) but not setting managedProperty to false. (because this property makes it no longer maintained in the right position)

Upvotes: 1

Views: 868

Answers (1)

fabian
fabian

Reputation: 82511

You need to override the computation of the minimal node width for this purpose. If you also want to hide parts of the node outside of the of the bounds, you need to apply a clip to the layout.

Example:

public class ShrinkableHBox extends HBox {

    private final int unshrinkableCount;

    public ShrinkableHBox(int unshrinkableCount) {
        final Rectangle clip = new Rectangle();
        clip.widthProperty().bind(widthProperty());
        clip.heightProperty().bind(heightProperty());
        setClip(clip);
        this.unshrinkableCount = unshrinkableCount;
    }

    @Override
    protected double computeMinWidth(double height) {
        Insets insets = getInsets();
        height -= insets.getTop() + insets.getBottom(); 
        double width = insets.getLeft() + insets.getRight();

        List<Node> children = getManagedChildren();

        int unshrinkableCount = Math.min(children.size(), this.unshrinkableCount);

        // only consider the first unshrinkableCount children for minWidth computation
        if (unshrinkableCount > 1) {
            width += getSpacing() * (unshrinkableCount - 1);
        }

        for (int i = 0; i < unshrinkableCount; i++) {
            width += children.get(i).minWidth(height);
        }

        return width;
    }

}
@Override
public void start(Stage primaryStage) {
    // custom hbox with 2 resizeable 
    ShrinkableHBox hbox = new ShrinkableHBox(1);
    hbox.getChildren().addAll(
            new Rectangle(100, 100, Color.RED),
            new Rectangle(100, 100, Color.BLUE)
    );
    hbox.setOpacity(0.5);

    Scene scene = new Scene(new HBox(hbox, new Rectangle(100, 100, Color.GREEN.interpolate(Color.TRANSPARENT, 0.5))));
    primaryStage.setScene(scene);
    primaryStage.show();
}

Note that simply replacing the Text node with a Label could also be a solution, since this allows you to shorten the text with ellipsis, if the space is not sufficient.

Upvotes: 1

Related Questions