Takasur
Takasur

Reputation: 462

javafx gridpane center align and justify all labels

The idea is to create a submission form that has many labels centered and justified for example:

Label 1 is Customer Name and Label 2 is Product Name What I am trying to do is horizontally center align all the labels that's very easy but At the same time I want them justified. In short P should come exactly below C in second row of gridpane.

Upvotes: 1

Views: 1069

Answers (1)

fabian
fabian

Reputation: 82451

Note that the widest node in every column is responsible to determine the start x coordinate. If the nodes are centered, you need to move all nodes by half the difference of the node's width to the max width to the left, which can be achieved using the translateX property:

Example

@Override
public void start(Stage primaryStage) {
    GridPane gp = new GridPane();
    ColumnConstraints constraints = new ColumnConstraints();
    constraints.setHalignment(HPos.CENTER);
    constraints.setPercentWidth(50);

    gp.getColumnConstraints().addAll(constraints, constraints);
    Random random = new Random();

    Node[][] elements = new Node[2][10];

    for (int x = 0; x < elements.length; x++) {
        final Node[] column = elements[x];
        InvalidationListener sizeListener = o -> {
            // determine max width
            double maxSize = 0;

            for (Node n : column) {
                double width = n.getLayoutBounds().getWidth();
                if (width > maxSize) {
                    maxSize = width;
                }
            }

            // adjust translate
            for (Node n : column) {
                n.setTranslateX((n.getLayoutBounds().getWidth() - maxSize) / 2);
            }
        };

        // fill column with strings of random lenght
        for (int y = 0; y < 10; y++) {
            int charCount = random.nextInt(30);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < charCount; i++) {
                sb.append('a');
            }
            Label text = new Label(sb.toString());
            text.layoutBoundsProperty().addListener(sizeListener);
            column[y] = text;
        }
        gp.addColumn(x, column);
        sizeListener.invalidated(null);
    }

    Scene scene = new Scene(gp);

    primaryStage.setScene(scene);
    primaryStage.show();
}

Edit

Even though you cannot do this with SceneBuilder, you can apply this kind of alignment to a GridPane from fxml, if you implement the logic to add this functionality in a utility class and use that utility class from the fxml.

public final class WeirdAlign {

    private WeirdAlign() {
    }

    public static final Predicate<Node> ALL_PREDICATE = n -> true;

    public static void setCombinedCenterJustify(GridPane gridPane, Predicate<Node> predicate) {
        InvalidationListener listener = o -> {
            Node n = (Node) ((ReadOnlyProperty) o).getBean();
            updateGridPaneColumn(gridPane, getGridPaneColumn(n), predicate);
        };
        ObservableList<Node> children = gridPane.getChildren();

        for (Node n : children) {
            if (predicate.test(n)) {
                n.layoutBoundsProperty().addListener(listener);
            }
        }

        int[] columns = children.stream().filter(predicate).mapToInt(WeirdAlign::getGridPaneColumn).distinct().toArray();
        for (int i : columns) {
            updateGridPaneColumn(gridPane, i, predicate);
        }

        children.addListener((ListChangeListener.Change<? extends Node> c) -> {
            Set<Integer> columnsToUpdate = new HashSet<>();
            while (c.next()) {
                if (c.wasRemoved()) {
                    for (Node n : c.getRemoved()) {
                        if (predicate.test(n)) {
                            n.layoutBoundsProperty().removeListener(listener);
                            columnsToUpdate.add(getGridPaneColumn(n));
                        }
                    }
                }
                if (c.wasAdded()) {
                    for (Node n : c.getAddedSubList()) {
                        if (predicate.test(n)) {
                            n.layoutBoundsProperty().addListener(listener);
                            columnsToUpdate.add(getGridPaneColumn(n));
                        }
                    }
                }
            }
            for (Integer i : columnsToUpdate) {
                updateGridPaneColumn(gridPane, i, predicate);
            }
        });
    }

    /**
     * This method is only here for FXMLLoader.
     */
    public static Predicate<Node> getCombinedCenterJustify(GridPane node) {
        throw new UnsupportedOperationException();
    }

    public static void updateGridPaneColumn(GridPane gridPane, int column, Predicate<Node> predicate) {
        double maxSize = 0;
        for (Node child : gridPane.getChildren()) {
            if (column == getGridPaneColumn(child) && predicate.test(child)) {
                double width = child.getLayoutBounds().getWidth();
                if (width > maxSize) {
                    maxSize = width;
                }
            }
        }
        for (Node child : gridPane.getChildren()) {
            if (column == getGridPaneColumn(child) && predicate.test(child)) {
                child.setTranslateX((child.getLayoutBounds().getWidth() - maxSize) / 2);
            }
        }
    }

    public static int getGridPaneColumn(Node node) {
        Integer c = GridPane.getColumnIndex(node);
        return c == null ? 0 : c;
    }

}
<GridPane xmlns:fx="http://javafx.com/fxml/1" id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.60" >
    <columnConstraints>
        <ColumnConstraints fx:id="c1" fillWidth="false" halignment="CENTER" percentWidth="50.0" />
        <fx:reference source="c1"/>
    </columnConstraints>
   <children>
      <Label text="abfkaenlgen" />
      <Label text="z7492z4z58z4zu uzu53 9zu59h 5n 54uhn" GridPane.columnIndex="1" GridPane.rowIndex="2" />
      <Label text="bbdnfkbner" GridPane.columnIndex="1" GridPane.rowIndex="1" />
      <Label text="hhhhhddddssaaeeeaaae" GridPane.rowIndex="1" />
      <Label text="gjnwkeibrgbawhgbreökbrgesöbrgsnrgs" GridPane.rowIndex="2" />
   </children>
   <WeirdAlign.combinedCenterJustify>
       <WeirdAlign fx:constant="ALL_PREDICATE"/>
   </WeirdAlign.combinedCenterJustify>
</GridPane>

Upvotes: 2

Related Questions