TitledPane not resized vertically when using a TextFlow in a custom control

324 Views Asked by At

I'm using a TextFlow with a Text inside a custom JavaFX control and this control is placed in a TitledPane.

Control declaration :

public class CustomControl extends Control {
    @Override
    protected Skin<?> createDefaultSkin() {
        return new CustomControlSkin(this);
    }
}

Skin declaration :

public class CustomControlSkin extends SkinBase<CustomControl> implements Skin<CustomControl> {
    public CustomControlSkin(CustomControl customControl) {
        super(customControl);
        TextFlow textFlow = new TextFlow();
        textFlow.getChildren().add(new Text("This is a long long long long long long long long long long long long long long text"));
        getChildren().add(new StackPane(textFlow));
    }
}

Application :

@Override
public void start(Stage primaryStage) throws Exception {
    TitledPane titledPane = new TitledPane();
    titledPane.setContent(new CustomControl());
    Scene scene = new Scene(new StackPane(titledPane));
    primaryStage.setScene(scene);
    primaryStage.show();
}

When the Scene get resized horizontally, the Text gets wrapped and its height increases. However, the TitledPane doesn't get resized vertically.

TextFlow used in a custom control

This does not happen when the TextFlow is placed directly in the TitledPane without using a custom control.

TextFlow used directly in the TitledPane

Using the Scenic View I have noticed that when the TextFlow is used in the custom control, the layout bounds of the control differ from the bounds in parent. Actually, the bounds in parent seems to be correctly computed, but not used.

Scene graph

This might be the source of this issue. I have experimented will all compute(Min/Pref/Max)Height methods of the Skin but did not managed to get the TitledPane being resized correctly.

Any idea why the TextFlow behave differently when used in a custom control/skin and how to get the TitledPane being resized correctly?

1

There are 1 best solutions below

1
On BEST ANSWER

I reported this issue to Oracle and this was accepted as a JavaFX bug : JDK-8144128

As a workaround for this bug, I have done the following :

  • Set control content bias to Orientation.HORIZONTAL

    public class CustomControl extends Control {
        @Override
        protected Skin<?> createDefaultSkin() {
            return new CustomControlSkin(this);
        }
    
        @Override
        public Orientation getContentBias() {
            return Orientation.HORIZONTAL;
        }
    }
    
  • Override skin computeMinHeight to use node width instead of -1 when calling node.minHeight

    public class CustomControlSkin extends SkinBase<CustomControl> implements Skin<CustomControl> {
        public CustomControlSkin(CustomControl customControl) {
            super(customControl);
            TextFlow textFlow = new TextFlow();
            textFlow.getChildren().add(new Text("This is a long long long long long long long long long long long long long long text"));
            getChildren().add(new StackPane(textFlow));
        }
    
        @Override
        protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
            double minY = 0;
            double maxY = 0;
            boolean firstManagedChild = true;
            for (int i = 0; i < getChildren().size(); i++) {
                Node node = getChildren().get(i);
                if (node.isManaged()) {
                    final double y = node.getLayoutBounds().getMinY() + node.getLayoutY();
                    if (!firstManagedChild) {
                        minY = Math.min(minY, y);
                        maxY = Math.max(maxY, y + node.minHeight(width));
                    } else {
                        minY = y;
                        maxY = y + node.minHeight(width);
                        firstManagedChild = false;
                    }
                }
            }
            double minHeight = maxY - minY;
            return topInset + minHeight + bottomInset;
         }
    }