Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preferred height of a control skin containing a wrapped label

I wrote a basic control and its skin. A label is displayed in a HBox in the skin. This label should wrap its text if there isn't enough space.

public class LabelWrap extends Application {

    public static void main(String[] args) {
        launch(LabelWrap.class);
    }

    @Override
    public void start(Stage stage) throws Exception {
        BasicControl basicControl = new BasicControl();
        BorderPane borderPane = new BorderPane();
        borderPane.setPrefWidth(150);
        borderPane.setCenter(basicControl);

        stage.setScene(new Scene(borderPane));
        stage.centerOnScreen();
        stage.show();
    }

    private static class BasicControl extends Control {
        @Override
        protected Skin<?> createDefaultSkin() {
            return new BasicControlSkin(this);
        }
    }

    private static class BasicControlSkin extends SkinBase<BasicControl> {
        protected BasicControlSkin(BasicControl control) {
            super(control);
            VBox box = new VBox();
            Label label = new Label("This text should wrap because it is too long");
            label.setWrapText(true);
            box.getChildren().add(label);
            getChildren().add(box);
        }
    }
}

But the label does not wrap (the ellipsis is displayed) because the preferred width of my control is not correctly computed:

actual label behavior

what i want to obtain is:

expected label behavior

How can i configure the skin to compute the skin preferred height to obtain the desired behavior (i never want an ellipsis displayed) ?

Notes:

  • i don't want to set an explicit maximum size on the label or on other skin components: label.setMaxWidth(150). The sole explicit width set should be the root BorderPane in the start method. This width (150) could be variable, the control could be used in different place.
  • this basic control is of course a simplification of the real one. The real one displays several Label with variable texts inside.
  • the label wraps correctly if i augment the window height until it has enough space
  • this code is running on java 1.8.0_40-b27 on a OSX 10.10.2
like image 788
gontard Avatar asked May 12 '15 10:05

gontard


1 Answers

AFAIK, to wrap a text in a label you should define a width to this label because referring to the setWrapText(Boolean) documentation:

public final void setWrapText(boolean value)

Sets the value of the property wrapText.

Property description: If a run of text exceeds the width of the Labeled, then this variable indicates whether the text should wrap onto another line.

Here the statement exceeds the width of the Labeled induce that you have already defined a width for your label, that's why you can't use it when there's no width defined.

So your code should be:

    Label label = new Label("This text should wrap because it is too long");
    label.setMaxWidth(150);
    label.setWrapText(true);

Another alternative is to use a Text element instead of a Label and use the method setWrappingWidth() like this:

Text t = new Text("This text should wrap because it is too long"  );
t.setWrappingWidth(150);

And you will get this result:

Wrap text result

Conclusion:

To wrap a text (either in a Label or in a Text element) you have to define a width so the text will return to a new line when we exceed this width.

EDIT:

And to make it a little bit more dynamic and avoid setting a width to your label, and if you are setting a PrefWidth to your borderPaneyou can use a static double WIDTH that will get this PrefWidth and set it to the MaxWidth of the label, here's the example code:

public class LabelWrap extends Application {

    static double WIDTH;

    public static void main(String[] args) {
        launch(LabelWrap.class);
    }

    @Override
    public void start(Stage stage) throws Exception {
        BasicControl basicControl = new BasicControl();
        BorderPane borderPane = new BorderPane();
        borderPane.setPrefWidth(150);
        borderPane.setCenter(basicControl);

        //get the PrefWidth value in the WIDTH attribute
        WIDTH = borderPane.getPrefWidth();
        stage.setScene(new Scene(borderPane));
        stage.centerOnScreen();
        stage.show();
    }

    private static class BasicControl extends Control {
        @Override
        protected Skin<?> createDefaultSkin() {
                return new BasicControlSkin(this);
        }
    }

    private static class BasicControlSkin extends SkinBase<BasicControl> {
        protected BasicControlSkin(BasicControl control) {
            super(control);
            VBox box = new VBox();
            Label label = new Label("This text should wrap because it is too long");

            //set the WIDTH value to the label MaxWidth
            label.setMaxWidth(WIDTH);
            label.setWrapText(true);
            box.getChildren().add(label);
            this.getChildren().add(box);
        }
    }
}
like image 190
cнŝdk Avatar answered Nov 12 '22 02:11

cнŝdk