0

I'm looking for a way to make a JavaFX pane always square no matter how the windows it's in is resized. The size should be determined by whatever is smaller, height or width. So it uses the maximum available space in whichever direction is smaller.

I made a simple example here:

This is the .fxml-File and I want paneInnerPane to be square at all times.

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>


<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.demo.MyController">
   <center>
      <VBox fx:id="vBoxCenter" BorderPane.alignment="CENTER">
         <children>
            <StackPane fx:id="stackPaneOuterPane" minHeight="800.0" minWidth="800.0">
               <children>
                  <Pane fx:id="paneinnerPane" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: red;" />
               </children>
            </StackPane>
            <ButtonBar prefHeight="40.0" prefWidth="200.0">
              <buttons>
                <Button mnemonicParsing="false" text="Button" />
                  <Button mnemonicParsing="false" text="Button" />
              </buttons>
            </ButtonBar>
         </children>
      </VBox>
   </center>
</BorderPane>

This is the Controller and the main class:

public class MyController {

    public VBox vBoxCenter;
    public StackPane stackPaneOuterPane;
    public Pane paneinnerPane;

    @FXML
    public void initialize() {
        VBox.setVgrow(paneinnerPane, Priority.ALWAYS);
    }

    @FXML
    private Label welcomeText;

    @FXML
    protected void onHelloButtonClick() {
        welcomeText.setText("Welcome to JavaFX Application!");
    }
}

public class MyApplication extends Application {
    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(MyApplication.class.getResource("myview.fxml"));
        Scene scene = new Scene(fxmlLoader.load());
        stage.setTitle("Hello!");
        stage.setScene(scene);
        stage.show();
    }

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

I tried thinks like this:

    paneinnerPane.prefHeightProperty().bind(paneinnerPane.widthProperty());
    paneinnerPane.prefWidthProperty().bind(paneinnerPane.heightProperty());

(Also with minWidth and maxWidth)

But the result is always the same:

enter image description here

The red rectangle should be square.

What do I have to do to make a Pane always be a square?

Wewius
  • 87
  • 7
  • _The size should be determined by whatever is smaller, height or width_ is a bit of a hen-egg problem, might depend on the inner workings of the layout pane (in what sequence it queries the width/height constraints of the square node). Enforcing the square could be the task of the node (implement getXX(double) to return the same as the given dimension (beware: didn't try, guesswork ;) BTW: don't hard-code sizing constraints. – kleopatra Jan 28 '23 at 16:06
  • Thanks. I fixed it even though it was just a hasty put together example and not indicative of my actual code. In the meantime, I tried to solve this problem with changeListeners on the height and width property but that didn't work either. – Wewius Jan 28 '23 at 16:07
  • don't use listeners .. it's a layout problem, solve it by layout api. What is supposed to be contained in the square pane, arbitrary children or anything special? – kleopatra Jan 28 '23 at 16:09
  • Okay. Then I won't use properties or listeners. But how do I solve this problem using the layout api? I'm sorry if this is a mundane question. I'm still trying to wrap my head around MVC pattern and how all of this works. – Wewius Jan 28 '23 at 16:14
  • In this square pane is going to be a grid. Imagine something like a chess board or minesweeper like. The elements in this plane will be intractable with and when I resize the main window, I want the elements to change size too. Let's say the pane is 800x800 in size and the grid within it contains 8 rows and columns. There fore every row and column should have 100px width and height. – Wewius Jan 28 '23 at 16:25
  • 2
    Create a subclass of `Pane` or `Region` and use it as the container for your square pane. Override `layoutChildren` to resize and center the square pane. – James_D Jan 28 '23 at 16:40
  • 2
    A layout example cited [here](https://stackoverflow.com/a/31761362/230513) shows how to "scale a background image while retaining its aspect ratio." See also this [alternative](https://stackoverflow.com/a/70312046/230513). – trashgod Jan 28 '23 at 19:47

0 Answers0