Предпочтительная высота управляющей оболочки, содержащей обернутую этикетку

Я написал базовый элемент управления и его кожу. A label отображается в HBox на коже. Этот ярлык должен обернуть его текст, если места недостаточно.

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);
        }
    }
}

Но метка не обертывается (отображается многоточие), потому что предпочтительная ширина моего элемента управления неправильно вычисляется:

actual label behavior

что я хочу получить:

expected label behavior

Как настроить скин, чтобы вычислить предпочтительную высоту скина, чтобы получить желаемое поведение (я никогда не хочу показывать эллипсис)?

Примечания:

  • Я не хочу устанавливать явный максимальный размер на ярлыке или на других компонентах скина: label.setMaxWidth(150). Единственным явным набором ширины должен быть корень BorderPane в start method. Эта ширина (150) может быть переменной, элемент управления может использоваться в разных местах.
  • Этот базовый элемент управления, конечно, является упрощением реального. Реальный показывает несколько label с переменными текстами внутри.
  • ярлык обертывается правильно, если я увеличиваю высоту окна, пока не будет достаточно места.
  • этот код работает на java 1.8.0_40-b27 на OSX 10.10.2

Ответ 1

AFAIK, чтобы обернуть text в label, вы должны определить width для этой метки, потому что ссылаясь на setWrapText (Boolean):

public final void setWrapText (логическое значение)

Устанавливает значение свойства wrapText.

Описание свойства:Если пробег текста превышает ширину метки, то эта переменная указывает, должен ли текст переноситься на другую строку.

Здесь выражение превышает ширину маркированного, которое вы уже определили width для вашего label, поэтому вы не можете использовать его, если нет width.

Итак, ваш код должен быть:

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

Другой альтернативой является использование Текстовый элемент вместо label и использовать метод setWrappingWidth() вот так:

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

И вы получите этот результат:

Wrap text result

Вывод:

Чтобы обернуть текст (либо в элементе label, либо в элементе text), вы должны определить ширину, чтобы текст возвращался к новой строке, когда мы превышаем эту ширину.

EDIT:

И чтобы сделать его немного более динамичным и не устанавливайте ширину вашей метки, и если вы устанавливаете PrefWidth на свой borderPane, вы можете использовать static double WIDTH, который получит этот PrefWidth и установите его на MaxWidth метки, здесь пример кода:

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);
        }
    }
}