文档



JavaFX:在JavaFX中使用布局

2 节点大小和对齐的技巧

本主题描述了在JavaFX布局面板中放置节点时控制节点大小和对齐的技术。

使用内置的JavaFX布局面板的主要优势是,节点的大小和对齐由面板处理。随着面板的调整大小,节点根据其首选大小范围偏好进行调整大小。请注意,并非所有节点类都是可调整大小的。UI控件和布局面板是可调整大小的,但形状、Text对象和Group对象不可调整大小,并在布局中被视为刚性对象。

如果您想更精确地控制UI中控件的大小,可以直接设置它们的首选大小范围。然后布局面板将使用您的设置来确定控件的大小。要管理控件的位置,可以使用布局面板的对齐属性。

本主题提供了在面板中调整节点大小和对齐的简单示例。文件LayoutSizingAligning.java包含了本主题中描述的示例的源代码。文件LayoutSizingAligning.zip包含了示例的NetBeans IDE项目。

节点大小调整

布局通过调用prefWidth(height)prefHeight(width)方法来查询节点的首选大小。默认情况下,UI控件根据控件的内容计算其首选大小的默认值。例如,Button对象的计算大小取决于文本的长度、用于标签的字体大小以及任何图像的大小。通常,计算出的大小刚好足够控件和标签完全可见。

UI控件还提供了默认的最小和最大大小,这些大小基于控件的典型用法。例如,Button对象的最大大小默认为其首选大小,因为通常不希望按钮任意增大。然而,ScrollPane对象的最大大小是无限的,因为通常希望它们能够填充其空间。

您可以使用节点的默认大小约束,也可以设置它们以获得所需的外观。例如,图2-1显示了边框面板中几个按钮和列表视图的默认大小。

图2-1 计算出的大小

图2-1的描述
"图2-1 计算出的大小"的描述

假设您想要的外观是图2-2中显示的屏幕,其中显示了根据所需约束调整大小的UI控件。

图2-2 所需的大小

图2-2的描述
"图2-2 所需的大小"的描述

应用程序通常需要直接设置控件的最小、首选和最大大小约束。以下各节提供了覆盖计算大小以获得所需外观的提示。

使按钮大小相同

您可以通过确定每个按钮的高度和宽度,然后将每个按钮的首选大小设置为按钮集中最大的高度和宽度。更简单的方法是让布局面板来完成这项工作。您要使用的布局面板取决于您想要实现的效果。

使用VBox

2-1中的场景使用了一个VBox布局面板来放置右侧的按钮,并使用计算出的大小。按钮已经具有相同的高度,所以只需要改变宽度。

2-2中的场景使用了一个VBox面板,以利用默认行为,使VBox面板的宽度与其最宽元素的首选宽度相同。为了使所有按钮都能调整为VBox面板的宽度,每个按钮的最大宽度设置为Double.MAX_VALUE常量,这使得控件可以无限增长。使用最大值常量的替代方法是将最大宽度设置为特定值,例如80.0。

示例2-1演示了如何使用VBox面板使一列按钮具有相同的宽度。

示例2-1 将一列按钮设置为相同的宽度

BorderPane border = new BorderPane();
border.setPadding(new Insets(20, 0, 20, 20));

Button btnAdd = new Button("添加");
Button btnDelete = new Button("删除");
Button btnMoveUp = new Button("上移");
Button btnMoveDown = new Button("下移");

btnAdd.setMaxWidth(Double.MAX_VALUE);
btnDelete.setMaxWidth(Double.MAX_VALUE);
btnMoveUp.setMaxWidth(Double.MAX_VALUE);
btnMoveDown.setMaxWidth(Double.MAX_VALUE);

VBox vbButtons = new VBox();
vbButtons.setSpacing(10);
vbButtons.setPadding(new Insets(0, 20, 10, 20)); 
vbButtons.getChildren().addAll(btnAdd, btnDelete, btnMoveUp, btnMoveDown);

在布局大小和对齐示例中,使用边界面板来布局UI元素。按钮列放在边界面板的右侧区域,以限制按钮的大小为最宽按钮的首选宽度。边界面板的中心区域会扩展以填充任何可用空间,因此如果将VBox面板放在中心区域,VBox面板和按钮也会扩展。

使用TilePane

图2-1中的场景中,底部的按钮使用了一个HBox布局容器,并使用了计算出的大小。这些按钮具有不同的宽度和高度。

图2-2中的场景中,使用了一个水平的TilePane布局容器,以利用默认行为,使每个单元格(瓷砖)的大小相同。每个瓷砖的大小是容纳瓷砖容器中最大节点的首选大小所需的大小。

为了使按钮能够调整大小以适应瓷砖的大小,将最大宽度和高度设置为Double.MAX_VALUE常量。在示例2-2中,展示了如何使用瓷砖容器使一行按钮具有相同的宽度和高度。

示例2-2 将一行按钮设置为相同大小

Button btnApply = new Button("应用");
Button btnContinue = new Button("继续");
Button btnExit = new Button("退出");
btnExit.setStyle("-fx-font-size: 15pt;");

btnApply.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
btnContinue.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
btnExit.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);

TilePane tileButtons = new TilePane(Orientation.HORIZONTAL);
tileButtons.setPadding(new Insets(20, 10, 20, 0));
tileButtons.setHgap(10.0);
tileButtons.setVgap(8.0);
tileButtons.getChildren().addAll(btnApply, btnContinue, btnExit);

当窗口大小改变时,瓷砖不会被调整大小,因此按钮在放置在瓷砖容器中时不会改变大小。请注意,如果窗口的宽度减小,瓷砖容器中的按钮会改变位置,但不会变小。

保持节点在其首选大小

当舞台调整大小时,舞台内的布局面板可能会有更多或更少的空间来分配给它们包含的控件。每个布局面板都有自己的规则来根据控件的最小、首选和最大大小范围来分配空间。一般来说,具有默认最大大小为Double.MAX_VALUE的控件会扩展以填充其空间,而具有受限最大大小的控件不会扩展。例如,ListView对象具有无限制的最大大小。如果您想将高度限制为其首选大小,可以将最大大小设置为Control.USE_PREF_SIZE常量,如示例2-3所示。

示例2-3 将最大高度设置为首选高度

ListView<String> lvList = new ListView<>();
ObservableList<String> items = FXCollections.observableArrayList (
        "热狗", "汉堡包", "薯条", 
        "胡萝卜条", "鸡肉沙拉");
lvList.setItems(items);
lvList.setMaxHeight(Control.USE_PREF_SIZE);

默认情况下,按钮只会增长到其首选大小。但是,如果未覆盖最小宽度,按钮会缩小到标签显示为三个点(...)。为了防止按钮变得比其首选宽度更小,将其最小宽度设置为其首选宽度,如示例2-4所示。

示例2-4 将最小宽度设置为首选宽度

Button btnMoveDown = new Button("向下移动");
btnMoveDown.setMinWidth(Control.USE_PREF_SIZE);

控件的首选大小最初基于计算大小。您可以通过将首选大小约束设置为所选大小来覆盖默认首选大小。以下语句覆盖了列表视图的首选宽度:

lvList.setPrefWidth(150.0);

防止调整大小

如果您不希望节点的大小发生变化,请将最小、最大和首选大小设置为相同的大小。要仅防止宽度或高度发生变化,请将宽度或高度约束设置为相同的值。在示例2-5中,创建了一个列表,其中所有大小约束都设置为相同的宽度和高度值,以便列表的大小在窗口大小更改时不会改变。创建了一个按钮,其中所有宽度约束都设置为相同的值。

示例2-5 设置大小约束以防止调整大小

ListView<String> lvList = new ListView<String>();
lvList.setMinSize(150.0, Control.USE_PREF_SIZE);
lvList.setMaxSize(150.0, Control.USE_PREF_SIZE);

Button btnDelete = new Button("删除");
btnDelete.setMinWidth(80.0);
btnDelete.setPrefWidth(80.0);
btnDelete.setMaxWidth(80.0);

对齐内容

每个布局面板都有一种默认的方式来对齐面板内的节点。例如,在HBoxVBox布局面板中,节点是顶部对齐和左对齐的。在TilePaneFlowPane布局面板中,节点是居中对齐的。默认情况下,面板本身通常是顶部对齐和左对齐的。

您可以使用面板的setAlignment()方法来管理节点和面板的对齐方式。对齐常量在javafx.geometry包中的以下enum类型中可用:

  • HPos - 用于指定水平对齐的值。

  • Pos - 用于指定垂直和水平对齐的值。下划线左侧的值指定垂直对齐,下划线右侧的值指定水平对齐。例如,Pos.BOTTOM_LEFT将节点垂直对齐到底部,水平对齐到左边缘。

  • VPos - 用于指定垂直对齐的值。

图2-3是由示例2-6中的代码创建的。如果没有指定任何对齐约束,布局面板将放置在左上角。

图2-3 默认位置

图2-3的描述
"图2-3 默认位置"的描述

示例2-6 创建具有默认对齐的UI

GridPane grid = new GridPane();
    grid.setHgap(10);
    grid.setVgap(12);

    HBox hbButtons = new HBox();
    hbButtons.setSpacing(10.0);

    Button btnSubmit = new Button("提交");
    Button btnClear = new Button("清除");
    Button btnExit = new Button("退出");
    btnSubmit.setStyle("-fx-font-size: 15pt;");

    Label lblName = new Label("用户名:");
    TextField tfName = new TextField();
    Label lblPwd = new Label("密码:");
    PasswordField pfPwd = new PasswordField();

    hbButtons.getChildren().addAll(btnSubmit, btnClear, btnExit);
    grid.add(lblName, 0, 0);
    grid.add(tfName, 1, 0);
    grid.add(lblPwd, 0, 1);
    grid.add(pfPwd, 1, 1);
    grid.add(hbButtons, 0, 2, 2, 1);
}

假设您想要的外观是在图2-4中显示的屏幕,它将布局面板居中显示在屏幕上并更改控件的默认对齐方式。

图2-4 期望位置

图2-4的描述如下
"图2-4 期望位置"的描述

以下部分提供了覆盖默认位置的提示。

居中网格

要在场景中居中显示来自示例2-6的网格,请使用以下语句:

grid.setAlignment(Pos.CENTER);

对齐列中的控件

在所需的布局中,标签右对齐,字段左对齐。要在网格中实现这一点,使用ColumnConstraints类定义每列,并设置水平对齐约束。 示例2-7定义了来自示例2-6的网格的列。

示例2-7 在网格中定义列

GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(12);

ColumnConstraints column1 = new ColumnConstraints();
column1.setHalignment(HPos.RIGHT);
grid.getColumnConstraints().add(column1); 

ColumnConstraints column2 = new ColumnConstraints();
column2.setHalignment(HPos.LEFT);
grid.getColumnConstraints().add(column2); 

在列中右对齐控件的另一种方法是使用VBox布局容器。使用setAlignment()方法,如下所示:

VBox vbox = new VBox;
vbox.setAlignment(Pos.CENTER_RIGHT);

居中按钮

按钮是在跨越网格的两列中布置的HBox布局面板中。以下语句将按钮在示例2-6中居中:

hbButtons.setAlignment(Pos.CENTER);

HBox面板的setAlignment()方法将HBox面板居中于其布局区域,并将节点居中于HBox面板中。您可能更喜欢将HBox面板居中于行中,但将按钮在HBox面板中底部对齐,如图2-5所示。

图2-5 覆盖位置并底部对齐按钮

图2-5的描述
"图2-5 覆盖位置并底部对齐按钮"的描述

对于这种布局,将HBox面板放置在一个内部网格中的单个单元格中,并将该网格放置在外部网格的第三行中。将内部网格的对齐约束设置为居中网格,并将HBox面板的对齐约束设置为底部对齐内容,如示例2-8所示。

示例2-8 居中并底部对齐按钮

hbButtons.setAlignment(Pos.BOTTOM_CENTER);
hbButtons.getChildren().addAll(btnSubmit, btnClear, btnExit);

GridPane innergrid = new GridPane();
innergrid.setAlignment(Pos.CENTER);
innergrid.add(hbButtons, 0, 0);
grid.add(innergrid, 0, 2, 2, 1);

其他资源

要了解更多关于JavaFX中的布局面板的信息,请参阅javafx.scene.layout包在API文档中的相关内容。

应用程序文件

源代码 

NetBeans项目 

关闭窗口

目录

JavaFX:在JavaFX中使用布局

展开 折叠