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.
This does not happen when the TextFlow is placed directly in the TitledPane without using a custom control.
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.
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?
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;
}
}