0

It is fairly easy to use the standard layout Panes in JavaFX to get fixed padding around a content node.

However are there settings for any of the standard layout Panes that would put the content in the middle ¾ of the pane's width with padding of 1/8 of the width on each side?

1 Answers1

0

You can, as suggested by James_D, use a GridPane with the appropriate constraints to accomplish this. Here's an example:

import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
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.scene.layout.RowConstraints;
import javafx.stage.Stage;

public class App extends Application {

  @Override
  public void start(Stage primaryStage) {
    Region region = new Region();
    region.setStyle("-fx-background-color: firebrick;");

    GridPane grid = new GridPane();
    grid.setAlignment(Pos.CENTER);
    grid.add(region, 0, 0);

    ColumnConstraints cc = new ColumnConstraints(0, Region.USE_COMPUTED_SIZE, Double.MAX_VALUE);
    cc.setPercentWidth(75);
    cc.setHgrow(Priority.ALWAYS);
    cc.setHalignment(HPos.CENTER);
    grid.getColumnConstraints().add(cc);

    RowConstraints rr = new RowConstraints(0, Region.USE_COMPUTED_SIZE, Double.MAX_VALUE);
    rr.setPercentHeight(100);
    rr.setVgrow(Priority.ALWAYS);
    rr.setValignment(VPos.CENTER);
    grid.getRowConstraints().add(rr);

    primaryStage.setScene(new Scene(grid, 500, 300));
    primaryStage.show();
  }
}

Another option is to create your own layout which, assuming I didn't make a mistake, is not too difficult:

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.layout.Pane;

public class CustomPane extends Pane {

  // value should be between 0.0 (0%) and 1.0 (100%)
  private final DoubleProperty widthRatio =
      new SimpleDoubleProperty(this, "widthRatio", 0.75) {

        @Override
        protected void invalidated() {
          requestLayout();
        }
      };
  public final void setWidthRatio(double widthRatio) { this.widthRatio.set(widthRatio); }
  public final double getWidthRatio() { return widthRatio.get(); }
  public final DoubleProperty widthRatioProperty() { return widthRatio; }

  public CustomPane() {}

  public CustomPane(double widthRatio) {
    setWidthRatio(widthRatio);
  }

  @Override
  protected void layoutChildren() {
    double ratio = getWidthRatioClamped();
    double x = snappedLeftInset();
    double y = snappedTopInset();
    double w = getWidth() - snappedRightInset() - x;
    double h = getHeight() - snappedBottomInset() - y;

    // could do the same thing with the height if you want
    x = snapPositionX(x + ((w - w * ratio) / 2.0));
    w = snapSizeX(w * ratio);

    for (Node child : getManagedChildren()) {
      layoutInArea(child, x, y, w, h, -1.0, HPos.CENTER, VPos.CENTER);
    }
  }

  private double getWidthRatioClamped() {
    return Math.max(0.0, Math.min(1.0, getWidthRatio()));
  }
}

Note that both solutions will take the child nodes' min/pref/max widths and heights into account. If the child node is not resizable (e.g. ImageView, MediaView, etc.) then it won't work as expected. Though you can of course create workarounds for non-resizable nodes. For instance, here's another answer of mine which creates a "resizable ImageView".

Also, note that both solutions layout the children in the area available after the space taken up from any padding and borders is subtracted.

Slaw
  • 37,820
  • 8
  • 53
  • 80
  • Another way to create a custom layout would be to subclass GridPane with initialisation code that sets the row and column constraints that you suggested. (Thanks for the suggestions.) – DougStirling Mar 25 '20 at 01:10
  • That definitely works, though I hesitate to subclass solely to simplify configuration. I would be more likely to create some utility method if using the `GridPane` approach. – Slaw Mar 25 '20 at 02:03