Working in Java FX 2.2. The Scene has a horizontal width that is fixed but is unknown at compile time. I want to place 2 or more buttons in a horizontal row that completely fills the horizontal space in the Scene AND that are each exactly the same width. The number of buttons changes dynamically with the program state. What program snippet will accomplish this?
A bit cleaner solution with property binding:
HBox buttonLayout = new HBox();
buttonLayout.getChildren().add(button1);
buttonLayout.getChildren().add(button2);
int btnCount = buttonLayout.getChildren().size();
button1.prefWidthProperty().bind(buttonLayout.widthProperty().divide(btnCount));
button2.prefWidthProperty().bind(buttonLayout.widthProperty().divide(btnCount));
This code from the HBox javadoc will almost do what you want, except that "buttons themselves are different sizes based on the text contained in the button - wider text causes wider buttons".
HBox hbox = new HBox();
Button button1 = new Button("Add");
Button button2 = new Button("Remove");
HBox.setHgrow(button1, Priority.ALWAYS);
HBox.setHgrow(button2, Priority.ALWAYS);
button1.setMaxWidth(Double.MAX_VALUE);
button2.setMaxWidth(Double.MAX_VALUE);
hbox.getChildren().addAll(button1, button2);
By creating a custom layout pane based on HBox and overriding it's layout method, you can get exactly the behaviour you describe.
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.control.Button;
import javafx.scene.layout.*;
import javafx.stage.Stage;
// displays equal width buttons which fill a layout region's width.
// http://stackoverflow.com/questions/12830402/javafx-2-buttons-size-fill-width-and-are-each-same-width
public class HorizontallyTiledButtons extends Application {
public static void main(String[] args) { launch(args); }
@Override public void start(Stage stage) {
final Button addButton = new Button("Add");
final Button removeButton = new Button("Remove");
final Button extraButton = new Button("The wizard of Frobozz is watching");
final ButtonBar buttonBar = new ButtonBar(5, addButton, removeButton);
addButton.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent event) {
buttonBar.addButton(extraButton);
}
});
removeButton.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent event) {
buttonBar.removeButton(extraButton);
}
});
VBox layout = new VBox(10);
layout.getChildren().addAll(buttonBar);
layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10;");
stage.setScene(new Scene(layout));
stage.setWidth(800);
stage.show();
}
class ButtonBar extends HBox {
ButtonBar(double spacing, Button... buttons) {
super(spacing);
getChildren().addAll(buttons);
for (Button b: buttons) {
HBox.setHgrow(b, Priority.ALWAYS);
b.setMaxWidth(Double.MAX_VALUE);
}
}
public void addButton(Button button) {
HBox.setHgrow(button, Priority.ALWAYS);
button.setMaxWidth(Double.MAX_VALUE);
ObservableList<Node> buttons = getChildren();
if (!buttons.contains(button)) {
buttons.add(button);
}
}
public void removeButton(Button button) {
getChildren().remove(button);
}
@Override protected void layoutChildren() {
double minPrefWidth = calculatePrefChildWidth();
for (Node n: getChildren()) {
if (n instanceof Button) {
((Button) n).setMinWidth(minPrefWidth);
}
}
super.layoutChildren();
}
private double calculatePrefChildWidth() {
double minPrefWidth = 0;
for (Node n: getChildren()) {
minPrefWidth = Math.max(minPrefWidth, n.prefWidth(-1));
}
return minPrefWidth;
}
}
}
Sample program output:
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