My first attempt at playing with JavaFX and I'm trying to understand a little bit about layout management. How do we access the preferred size of a control?
In the example below I am attempting to set the maximum width 200 pixels greater than the preferred width. That is, I want to allow the button to grow (up to a maximum) as the width of the frame is increased.
However when I run the code the preferred width is -1, so adding 200 to the preferred width gives a maximum width of 199.
import javafx.application.Application;
import javafx.event.*;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.geometry.Insets;
public class BorderPaneSSCCE extends Application
{
@Override
public void start(Stage primaryStage)
{
Button button = new Button( "Button at PreferredSize" );
button.setMaxWidth( button.getPrefWidth() + 200 );
System.out.println(button.prefWidth(-1) + " : " + button.getPrefWidth());
button.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
System.out.println("Width: " + button.getWidth());
}
});
HBox root = new HBox();
HBox.setHgrow(button, Priority.ALWAYS);
root.getChildren().add(button);
Scene scene = new Scene(root);
primaryStage.setTitle("Java FX");
primaryStage.setScene(scene);
primaryStage.show();
System.out.println(button.prefWidth(-1) + " : " + button.getPrefWidth());
}
public static void main(String[] args)
{
launch(args);
}
}
When I run the code and click on the button I see: Width: 139.0
After I resize the width of the frame so the button is as large as possible and I click on the button I see: Width: 199.0
I was hoping to see Width: 339.0
(ie. 139 + 200)
So, how do we access the preferred size/width of a control?
What Control's Install Size Is. Thankfully, the install size of Control isn't too large. On PS4, it comes in at just 24.4 GB. That's the only version we've been able to test right now, but the Microsoft Store, where you can preorder the game, says that it will come in at 34.75 GB on Xbox One.
The Anchor Property determines how a control is automatically resized when its parent control is resized. It defines the position for the control on the form. When designing a form that can be resized at run-time, the controls on the form should resize and reposition accordingly.
This property enables you to set the starting position of the form when it is displayed at run time. The form's position can be specified manually by setting the Location property or use the default location specified by Windows.
The TableLayoutPanel control arranges its contents in a grid. Because the layout is done both at design time and run time, it can change dynamically as the application environment changes.
getPrefWidth()
returns the USE_COMPUTED_SIZE
flag (which is -1) by default.
You can use prefWidth(-1)
to get the internally computed preferred width. However the preferred width will not be calculated until the node is being layed out by the layout pane (HBox in your example). This happens the first time when the stage is shown.
You have multiple options, if you want the maximum width to depend on the preferred width. One is to set the preferred width to a fixed value with setPrefWidth()
prior to setting the maximum width.
Another is to implement a custom layout algorithm - either on the node or on a layout pane. Here is an example using a custom button.
// button whose maxWidth is always prefWidth + 200
Button button = new Button() {
@Override
protected double computeMaxWidth(double height)
{
return this.prefWidth(height) + 200.0;
}
};
-1
is the value of Region.USE_COMPUTED_SIZE
, which tells the component to figure out it's own best size. This works because every Node
has a method called prefWidth(double height)
and it's double prefHeight(double width)
(the same for min/max size) that layout managers use for calculating the layout of their children. To get the pref size you need to use
button.prefWidth([-1 or Region.USE_COMPUTED_SIZE])
(docs)
getPrefWidth()
only works after the Node
has been shown / rendered.
You can either show the Button
first or try to use Node.prefWidth(-1)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With