Issue
I have an HBox that contains a square VBox in the center. The HBox width can be made larger than it's height, leaving extra space on the sides. I want to fill this extra space on the left and right with separate VBoxes where I will put buttons, info, etc. I want these two VBoxes, the "side panels," to always be of equal width. However, as you can see from the image below, when the right panel has a button and the left does not, it is wider than the left panel:
I thought
rightPanel.minWidthProperty().bindBidirectional(leftPanel.minWidthProperty());
rightPanel.prefWidthProperty().bindBidirectional(leftPanel.prefWidthProperty());
would do the trick, but it didn't.
Here's my code:
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.NumberBinding;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Control;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class FX010 extends Application{
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
GamePanel gp = new GamePanel();
Scene scene = new Scene(gp, 800, 600);
primaryStage.setTitle("testing");
primaryStage.minWidthProperty().bind(primaryStage.heightProperty());
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
public class GamePanel extends HBox{
public GamePanel() {
this.setMinHeight(400);
final VBox boardBox = new VBox();
boardBox.alignmentProperty().set(Pos.CENTER);
this.alignmentProperty().set(Pos.CENTER);
VBox leftPanel, rightPanel;
leftPanel = new VBox();
rightPanel = new VBox();
leftPanel.setBorder(new Border(new BorderStroke(Color.DARKRED, BorderStrokeStyle.SOLID,
CornerRadii.EMPTY,new BorderWidths(1))));
rightPanel.setBorder(new Border(new BorderStroke(Color.DARKRED, BorderStrokeStyle.SOLID,
CornerRadii.EMPTY,new BorderWidths(1))));
rightPanel.minWidthProperty().bindBidirectional(leftPanel.minWidthProperty());
rightPanel.prefWidthProperty().bindBidirectional(leftPanel.prefWidthProperty());
rightPanel.getChildren().add(new Button("testtesttest"));
HBox.setHgrow(leftPanel, Priority.ALWAYS);
HBox.setHgrow(rightPanel, Priority.ALWAYS);
StackPane board = new StackPane(new Rectangle(100,100,Color.RED));
board.setBorder(new Border(new BorderStroke(Color.DARKBLUE, BorderStrokeStyle.DASHED,
CornerRadii.EMPTY,new BorderWidths(1))));
final NumberBinding binding = Bindings.min(widthProperty(), heightProperty());
boardBox.prefWidthProperty().bind(binding);
boardBox.prefHeightProperty().bind(binding);
boardBox.setMaxSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE);
VBox.setVgrow(board, Priority.ALWAYS);
boardBox.getChildren().add(board);
getChildren().addAll(leftPanel, boardBox, rightPanel);
//HBox.setHgrow(this, Priority.ALWAYS);
}
}
}
How can I force leftPanel
to always have the same width as rightPanel
, while still ensuring that boardBox
is always a square?
Thanks!
Solution
After a lot of testing, I got this to work:
public class GamePanel extends HBox{
Pane leftPanel, rightPanel, iLeft, iRight;
VBox boardBox;
public GamePanel() {
this.setMinHeight(400);
iLeft = new Pane();
boardBox = new VBox();
iRight = new Pane();
boardBox.alignmentProperty().set(Pos.CENTER);
this.alignmentProperty().set(Pos.CENTER);
leftPanel = new Pane();
rightPanel = new Pane();
leftPanel.setBorder(new Border(new BorderStroke(Color.DARKRED, BorderStrokeStyle.SOLID,
CornerRadii.EMPTY,new BorderWidths(1))));
rightPanel.setBorder(new Border(new BorderStroke(Color.DARKRED, BorderStrokeStyle.SOLID,
CornerRadii.EMPTY,new BorderWidths(1))));
rightPanel.setPrefWidth(0);
leftPanel.setPrefWidth(0);
iRight.getChildren().add(new Button("testtesttest"));
rightPanel.getChildren().add(iRight);
HBox.setHgrow(leftPanel, Priority.ALWAYS);
HBox.setHgrow(rightPanel, Priority.ALWAYS);
StackPane board = new StackPane(new Rectangle(100,100,Color.RED));
board.setBorder(new Border(new BorderStroke(Color.DARKBLUE, BorderStrokeStyle.DASHED,
CornerRadii.EMPTY,new BorderWidths(1))));
final NumberBinding binding = Bindings.min(widthProperty(), heightProperty());
boardBox.prefWidthProperty().bind(binding);
boardBox.prefHeightProperty().bind(binding);
boardBox.setMaxSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE);
VBox.setVgrow(board, Priority.ALWAYS);
boardBox.getChildren().add(board);
getChildren().addAll(leftPanel, boardBox, rightPanel);
//HBox.setHgrow(this, Priority.ALWAYS);
}
}
This solution involves setting the left and right panel's prefWidth
to zero, then adding internal panes into each panel, which the content is then added to. I think the reason that this works is because space is allocated for the prefWidth before the panel's size is expanded by the Hgrow constraint. Since equal amounts of space are added to each panel by the HBox, the panel with a greater prefWidth ends up bigger. By setting both to zero, they both start with no prefWidth and thus end up at the same size. I believe that's also why anko's answer seemed to work - because when they start with equal prefWidths and the same amount of space is added to each, they end up with the same size. However, setting a prefWidth of 100 messes with the boardBox
's size (makes it not a square) when the stage's width is shrunk as small as possible.
I'm sure there is a better way to do this, and I'd be happy to accept a better answer.
Answered By - Sam Hooper
Answer Checked By - Robin (JavaFixing Admin)