2

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?

amischler
  • 128
  • 5

1 Answers1

2

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;
         }
    }
    
amischler
  • 128
  • 5
  • The fix did not work for me. However, the problem seems to be that the `Pane` wrapping the `TextFlow` computes its height by using its prefWidth **before any outer constraints restricting the width are applied**. This means that the `prefWidth` is equal to the `prefWidth` of the TextFlow, i.e. a single line, which is what the height calculation uses. I was able to work around this by just setting the prefWidth of the container surrounding the `TextFlow` to a fixed value. That means the wrapping occurs instantly. The problem is that this does not work with dynamic sizing, like requested here. – Timo Türschmann Apr 20 '18 at 10:16