GridPane не дает метке достаточно места при использовании столбцов с процентной шириной

Код ниже генерирует этот снимок экрана:

Ярлык не подходит

Метка под 2-м столбцом не хочет должным образом требовать дополнительного места, когда ее нужно обернуть. Это происходит только тогда, когда столбцы используют ширину в процентах — в документации говорится, что в этом случае будут игнорироваться все остальные свойства, включая hgrow и т. д., но не упоминается, что это также повлияет на работу строк.. но похоже, что это так.

У кого-нибудь есть работа или может сказать мне, что я делаю неправильно? Все, что я хочу, это отобразить 3 изображения с метками неизвестного размера под ними, которые хорошо расположены и выровнены, и все они одинакового размера... Что-то вроде этого:

Правильно перекомпонованные этикетки

Вышеупомянутое выполняется с помощью пользовательского элемента управления с предварительным названием «BetterGridPane»...

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.RowConstraints;
import javafx.stage.Stage;

public class TestLabelWrap extends Application {

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

  @Override
  public void start(Stage primaryStage) throws Exception {
    GridPane root = new GridPane();

    root.add(new ListView(FXCollections.observableArrayList("1", "2", "3")), 0, 0);
    root.add(new ListView(FXCollections.observableArrayList("1", "2", "3")), 1, 0);
    root.add(new ListView(FXCollections.observableArrayList("1", "2", "3")), 2, 0);

    root.add(new Label("Value A"), 0, 1);
    root.add(new Label("The value for this porperty is so large it wraps, The value for this porperty is so large it wraps") {{
      setWrapText(true);
    }}, 1, 1);
    root.add(new Label("Value C"), 2, 1);

    root.getColumnConstraints().add(new ColumnConstraints() {{ setPercentWidth(33.33); }});
    root.getColumnConstraints().add(new ColumnConstraints() {{ setPercentWidth(33.33); }});
    root.getColumnConstraints().add(new ColumnConstraints() {{ setPercentWidth(33.33); }});

    root.getRowConstraints().add(new RowConstraints() {{ setVgrow(Priority.NEVER); }});
    root.getRowConstraints().add(new RowConstraints() {{ setVgrow(Priority.ALWAYS); }});

    primaryStage.setScene(new Scene(root));
    primaryStage.show();
  }
}

person john16384    schedule 08.04.2019    source источник


Ответы (1)


Установка wrapText на true на самом деле кажется достаточной. Вы можете увидеть это, просто увеличив высоту вашего окна и наблюдая, как текст начинает оборачиваться (уменьшая ширину окна по мере необходимости). Проблема, кажется, заключается в GridPane и его начальных расчетах размера — он растет по горизонтали, чтобы вместить Label, но не по вертикали. Одно из исправлений состоит в том, чтобы просто указать Scene, GridPane или Label явную (предпочтительную) ширину, оставив высоту для вычисления.

  • new Scene(root, someWidth, -1)
  • root.setPrefWidth(someWidth)
  • label.setPrefWidth(someWidth) + label.setMaxWidth(Double.MAX_VALUE)

Однако, несмотря на то, что Javadoc ColumnConstraints.percentWidth говорит:

Если установлено значение больше 0, размер столбца будет изменен до этого процента доступной ширины области сетки, а другие ограничения размера (minWidth, prefWidth, maxWidth, hgrow) будут проигнорированы.

Похоже, что [min|pref|max]Width не игнорируется во время расчета предпочтительного размера. Поскольку у вас есть изображения известной и одинаковой ширины, вы должны иметь возможность установить предпочтительную ширину каждого ограничения так, чтобы она была немного больше, чем ширина изображения. Вот пример (с использованием OpenJDK 12 и OpenJFX 12):

import java.util.stream.Stream;
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;

public class Main extends Application {

    private static ColumnConstraints[] createColumnConstraints() {
        return Stream.generate(() -> {
            var constraint = new ColumnConstraints();
            constraint.setHalignment(HPos.CENTER);
            constraint.setPercentWidth(100.0 / 3.0);
            constraint.setPrefWidth(225.0); // SET PREF WIDTH
            return constraint;
        }).limit(3).toArray(ColumnConstraints[]::new);
    }

    private static Rectangle[] createRectangles() {
        return Stream.generate(() -> new Rectangle(100.0, 150.0)).limit(3).toArray(Rectangle[]::new);
    }

    private static Label[] createLabels(String... texts) {
        return Stream.of(texts).map(text -> {
            var label = new Label(text);
            label.setWrapText(true);
            label.setTextAlignment(TextAlignment.CENTER);
            return label;
        }).toArray(Label[]::new);
    }

    @Override
    public void start(Stage primaryStage) {
        var root = new GridPane();
        root.setGridLinesVisible(true); // FOR VISUAL CLARITY
        root.setHgap(10.0);
        root.setVgap(10.0);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(20.0));
        root.getColumnConstraints().addAll(createColumnConstraints());

        root.addRow(0, createRectangles());
        root.addRow(1, createLabels("Label A", "This is long text. ".repeat(10), "Label C"));

        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

}

Что приводит к:

скриншот пользовательского интерфейса, созданного с помощью примера кода


Предположение:

Поскольку вы используете new Scene(root), это означает, что размер Scene будет соответствовать предпочтительному размеру его содержимого. Это в основном дает корню свободу действий, чтобы расти настолько, насколько он сочтет необходимым. Как задокументировано GridPane:

По умолчанию размер строк и столбцов соответствует их содержимому; ширина столбца будет достаточной для размещения самого широкого дочернего элемента, а высота строки будет достаточной для размещения самого высокого дочернего элемента.

При использовании percentWidth ширина каждого столбца фактически не имеет верхней границы; они вырастут, чтобы соответствовать самому широкому ребенку. Кроме того, поскольку каждый столбец использует percentWidth, по мере роста одного из них растут все.

Это означает, что Label имеют практически неограниченное пространство для горизонтального роста, что означает, что предпочтительная высота Label рассчитывается как только одна строка текста; зачем обертывать, когда у вас бесконечная ширина? Из-за этого строка, которой принадлежат Labels, увеличивается только по вертикали настолько, чтобы вместить одну строку текста. Без места, чтобы обернуть текст выходит за пределы.

person Slaw    schedule 09.04.2019
comment
Изображения (соотношение) масштабируются до любого размера, который GridPane сочтет подходящим. По сути, я хочу, чтобы метки давали именно пространство, которое им нужно, чтобы они были полностью видны, а остальное — изображениям. Я не могу установить ширину или высоту, так как они неизвестны. Тем не менее, вы поставили меня на правильный путь, я немного изменил ваш пример, и он работает. Я удалил setPrefWidth, изменил прямоугольники на ListViews с высотой pref 1 и добавил RowConstraints ВСЕГДА и НИКОГДА к строкам 0 и 1 соответственно (противоположный тому, что у меня было... ключ, казалось, был той высотой pref в списках ). - person john16384; 09.04.2019