Button alignment in JavaFX

2019-04-27 21:26发布

I created this JavaFX dialog with Close button:

final int xSize = 300;
final int ySize = 280;
final Color backgroundColor = Color.WHITE;
final String text = "SQL Browser Version 1.0";

final Stage aboutDialog = new Stage();
aboutDialog.initModality(Modality.WINDOW_MODAL);

Button closeButton = new Button("Close");
closeButton.setAlignment(Pos.BOTTOM_CENTER);

closeButton.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent arg0) {
        aboutDialog.close();
    }
});

Scene aboutDialogScene = new Scene(VBoxBuilder.create()
    .children(new Text(text), closeButton)
    .alignment(Pos.CENTER)
    .padding(new Insets(10))
    .build(), xSize, ySize, backgroundColor);

aboutDialog.setScene(aboutDialogScene);
aboutDialog.show();

I want to display the button at the bottom of the dialog. I used this to set the alignment: closeButton.setAlignment(Pos.BOTTOM_CENTER); but for some reason the button is displayed at the center of the dialog. Can you tell me how I can fix this?

1条回答
祖国的老花朵
2楼-- · 2019-04-27 21:45

If you want to use a VBox for this, the method you are looking for is:

VBox.setVgrow(node, Priority.ALWAYS);


By default a VBox will just place children one under the other from the top left of where you place it. The children don't expand to fill all of the available vertical area, unless you set a Vgrow constraint on a child with an unbounded max height.

A few different ways you can get the layout you seek (there are others as well):

  1. Use a StackPane instead of a VBox and align your button with StackPane.setAlignment(closeButton, Pos.BOTTOM_CENTER);
  2. Use an AnchorPane instead of a VBox and set constraints on the AnchorPane appropriately.
  3. Use a spring region which is an empty Region which expands to fill empty space.

Sample spring region:

Region topSpring    = new Region();
Region bottomSpring = new Region();
Scene aboutDialogScene = new Scene(VBoxBuilder.create()
        .children(topSpring, new Text(text), bottomSpring, closeButton)
        .alignment(Pos.CENTER)
        .padding(new Insets(10))
        .build(), xSize, ySize, backgroundColor);
VBox.setVgrow(topSpring, Priority.ALWAYS);
VBox.setVgrow(bottomSpring, Priority.ALWAYS);

Calling closeButton.setAlignment(Pos.BOTTOM_CENTER); sets the alignment of things (text and graphic) within the closeButton, not the alignment of the closeButton within it's parent (which is what you really want).


For understanding how layout constraints work, SceneBuilder is a good tool to play around with and ScenicView can help debug layout issues in existing code.


Here are a few FXML samples of your layout that you can load up into SceneBuilder to see how the different layout options work.

All of the samples below can easily be written in plain java using the JavaFX API if you prefer. I wrote them in fxml as it makes the layouts easy to preview in SceneBuilder.

FXML sample using a StackPane:

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>

<StackPane id="StackPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="280.0" prefWidth="300.0" xmlns:fx="http://javafx.com/fxml">
  <children>
    <Label text="SQL Browser Version 1.0" />
    <Button mnemonicParsing="false" text="Button" StackPane.alignment="BOTTOM_CENTER" />
  </children>
  <padding>
    <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
  </padding>
</StackPane>

snapshot of fxml

And the same thing with some spring regions:

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>

<VBox alignment="CENTER" prefHeight="280.0" prefWidth="300.0" xmlns:fx="http://javafx.com/fxml">
  <children>
    <Region prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS" />
    <Label text="SQL Browser Version 1.0" />
    <Region prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS" />
    <Button mnemonicParsing="false" text="Close" />
  </children>
</VBox>

And the same thing with the label itself set to expand to fill empty space in the VBox:

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>

<VBox alignment="CENTER" prefHeight="280.0" prefWidth="300.0" xmlns:fx="http://javafx.com/fxml">
  <children>
    <Label maxHeight="1.7976931348623157E308" text="SQL Browser Version 1.0" VBox.vgrow="ALWAYS" />
    <Button mnemonicParsing="false" text="Close" />
  </children>
  <padding>
    <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
  </padding>
</VBox>
查看更多
登录 后发表回答