2

We need a solution for a 3 column layout with the following requirements:

  • The middle column has a fixed size
  • The middle column is centered in the parent
  • The other two columns both share the remaining space
  • The other two columns both have the same size

Let's say we have an amount of horizontal space of 440px and a middle column with a fixed size of 40px. The other two column should share the remaining 400px, so that each column has a width of 200px.

------------------------------------
|    200px    | 40px |    200px    |
------------------------------------

If the overall size changes, let's say to 500px, the width of the middle column should not change, but the others should.

----------------------------------------
|     230px     | 40px |     230px     |
----------------------------------------

If this is possible with a GridPane, please tell me how.

If this is not possible with a GridPane, I'm open for other suggestions.

I would prefer a solution with plain a) Java Code without FXML and b) JavaFx only, so extra libraries.

Guardian667
  • 417
  • 4
  • 16

1 Answers1

5

You just need three column constraints:

ColumnConstraints leftCol = new ColumnConstraints();
leftCol.setHgrow(Priority.ALWAYS);
ColumnConstraints middleCol = new ColumnConstraints(40);
ColumnConstraints rightCol = new ColumnConstraints();
rightCol.setHgrow(Priority.ALWAYS);

GridPane gridPane = new GridPane();
gridPane.getColumnConstraints().addAll(leftCol, middleCol, rightCol);

You can do the same in FXML if you prefer:

<GridPane>
  <columnConstraints>
    <ColumnConstraints hgrow="ALWAYS"/>
    <ColumnConstraints minWidth="40" prefWidth="40" maxWidth="40"/>
    <ColumnConstraints hgrow="ALWAYS"/>
  </columnConstraints>

  <!-- ... -->
</GridPane>

Here's a SSCCE:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.stage.Stage;

public class GridPaneTest extends Application {

    @Override
    public void start(Stage primaryStage) {
        ColumnConstraints leftCol = new ColumnConstraints();
        leftCol.setHgrow(Priority.ALWAYS);
        ColumnConstraints middleCol = new ColumnConstraints(40);
        ColumnConstraints rightCol = new ColumnConstraints();
        rightCol.setHgrow(Priority.ALWAYS);


        GridPane gridPane = new GridPane();
        gridPane.getColumnConstraints().addAll(leftCol, middleCol, rightCol);

        Region left = new Region();
        left.setMinHeight(80);
        left.setStyle("-fx-background-color: red;");

        Region middle = new Region();
        middle.setMinHeight(80);
        middle.setStyle("-fx-background-color: green ;");

        Region right = new Region();
        right.setMinHeight(80);
        right.setStyle("-fx-background-color: blue ;");

        gridPane.addRow(0, left, middle, right);

        Scene scene = new Scene(gridPane, 400, 80);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

enter image description here

enter image description here

James_D
  • 201,275
  • 16
  • 291
  • 322
  • That works, but my problem is not completely solved. I said "The middle column has a fixed size". In fact the grid contains only one row and the middle column contains one control. This control's size can change on runtime. In your example the green Region would change it's width and the GridPane has to react on it. Therefore I need an elaborated solution to share the remaining size less a dynamic size. That can't work with the constraints, without removing them, do recalculation and re-adding them "by hand". – Guardian667 Jan 19 '18 at 08:56
  • @Guardian667 I don't quite understand that comment. In my code, the middle column has a fixed size, as you specified in the question: it is always 40 pixels. Or are you saying you are changing the question? – James_D Jan 19 '18 at 10:05
  • Yeah, your example matches my explanation. My explanation was inaccurate respecting the problem. In my special case not the column itself is limited to a fixed size, but it's width is limited to the size of the control it contains. | x | control | x | The control can change in size, and on that change the remaining space must be distributed evenly. I'm doing it right now by recreating the constraints, when the size of the control changes, but maybe there's a more elegant solution. – Guardian667 Jan 19 '18 at 10:54
  • @Guardian667 Just replace `ColumnConstraints middleCol = new ColumnConstraints(40);` with `ColumnConstraints middleCol = new ColumnConstraints();`? (The `min`, `max`, and `prefWidth` default to `Region.USE_COMPUTED_SIZE`.) I think that should work assuming you are not doing anything unusual with the layout of the control contained in that column. – James_D Jan 19 '18 at 12:47
  • USE_COMPUTED_SIZE takes the same effect as Priority.ALLWAYS :( My solution for now: The ColumnConstraints for middle column are hold in a class parameter. Their min and max value is set to the desired width i as they become apparent. – Guardian667 Jan 25 '18 at 12:52
  • @Guardian667 So set the `hgrow` of that column explicitly to `Priority.NEVER`? – James_D Jan 25 '18 at 13:16
  • Already tried that. Maybe it only takes no effect in my special case. At the moment I'm fine with the solution. Release date lies ahead (waaaahhhhhhh ;-) – Guardian667 Jan 26 '18 at 08:45