1 使用内置布局面板
本主题介绍了JavaFX SDK提供的布局容器类,称为面板,用于轻松管理JavaFX应用程序的用户界面。
JavaFX应用程序可以通过设置每个UI元素的位置和大小属性来手动布局UI。然而,更简单的方法是利用布局面板。JavaFX SDK提供了几个布局面板,用于轻松设置和管理经典布局,如行、列、堆栈、平铺等。当窗口调整大小时,布局面板会根据节点的属性自动重新定位和调整节点的大小。
本主题提供了JavaFX布局包提供的每个布局面板的概述和简单示例。文件LayoutSample.java
包含了本主题中构建的UI的源代码。文件LayoutSample.zip
包含了示例应用程序的NetBeans IDE项目。
BorderPane
BorderPane
布局面板提供了五个区域来放置节点:顶部、底部、左侧、右侧和中心。 图1-1展示了使用边界面板可以创建的布局类型。这些区域可以是任意大小。如果你的应用程序不需要其中的某个区域,你不需要定义它,也不会为其分配空间。
边界面板适用于经典的界面布局,例如顶部的工具栏、底部的状态栏、左侧的导航面板、右侧的附加信息和中心的工作区域。
如果窗口比每个区域内容所需的空间大,多余的空间默认分配给中心区域。如果窗口比每个区域内容所需的空间小,区域可能会重叠。重叠的顺序由区域设置的顺序决定。例如,如果区域的顺序是左侧、底部和右侧,当窗口变小时,底部区域会重叠左侧区域,右侧区域会重叠底部区域。如果顺序是左侧、右侧和底部,当窗口变小时,底部区域会同时重叠左侧和右侧区域。
示例1-1展示了创建边界面板的代码,该面板用于布局示例应用程序构建的用户界面。在本主题的其余部分中,将介绍用于创建每个区域中使用的布局面板的方法。
示例1-1 创建边界面板
BorderPane border = new BorderPane(); HBox hbox = addHBox() border.setTop(hbox); border.setLeft(addVBox()); addStackPane(hbox); // 将堆栈添加到顶部区域的HBox中 border.setCenter(addGridPane()); border.setRight(addFlowPane());
请注意,此示例中未使用边界面板的底部区域。如果你想向底部区域添加内容,请使用以下语句,并将node替换为你选择的控件:
border.setBottom(node);
HBox
HBox
布局面板提供了一种简单的方式来将一系列节点排列在一行中。 图1-2显示了一个HBox
面板的示例。
可以设置padding属性来管理节点与HBox
面板边缘之间的距离。可以设置spacing来管理节点之间的距离。可以设置style来改变背景颜色。
示例1-2创建了一个包含两个按钮的工具栏的HBox
面板。
示例1-2 创建HBox面板
public HBox addHBox() { HBox hbox = new HBox(); hbox.setPadding(new Insets(15, 12, 15, 12)); hbox.setSpacing(10); hbox.setStyle("-fx-background-color: #336699;"); Button buttonCurrent = new Button("当前"); buttonCurrent.setPrefSize(100, 20); Button buttonProjected = new Button("预测"); buttonProjected.setPrefSize(100, 20); hbox.getChildren().addAll(buttonCurrent, buttonProjected); return hbox; }
VBox
VBox
布局面板与HBox
布局面板类似,只是节点按照单列排列。示例VBox
面板如图1-4所示。
可以通过设置padding属性来管理节点与VBox
面板边缘之间的距离。可以通过设置spacing来管理节点之间的距离。可以通过设置margins来在各个控件周围添加额外的空间。
示例1-3创建了一个用于选项列表的VBox
面板。
示例1-3 创建VBox面板
public VBox addVBox(); { VBox vbox = new VBox(); vbox.setPadding(new Insets(10)); vbox.setSpacing(8); Text title = new Text("数据"); title.setFont(Font.font("Arial", FontWeight.BOLD, 14)); vbox.getChildren().add(title); Hyperlink options[] = new Hyperlink[] { new Hyperlink("销售"), new Hyperlink("市场营销"), new Hyperlink("分销"), new Hyperlink("成本")}; for (int i=0; i<4; i++) { VBox.setMargin(options[i], new Insets(0, 0, 0, 8)); vbox.getChildren().add(options[i]); } return vbox; }
StackPane
StackPane
布局容器将所有节点放置在一个堆栈中,每个新节点都会叠加在前一个节点之上。这种布局模型提供了一种简单的方式,可以在形状或图像上叠加文本,或者重叠常见的形状以创建复杂的形状。图1-6显示了一个帮助图标,它是通过将一个问号叠加在具有渐变背景的矩形上创建的。
可以设置对齐属性来管理在堆栈面板中的子节点的位置。该属性影响所有子节点,因此可以设置边距来调整堆栈中各个子节点的位置。
示例1-4创建了一个用于帮助图标的堆栈面板。
示例1-4 创建Stack Pane
public void addStackPane(HBox hb) { StackPane stack = new StackPane(); Rectangle helpIcon = new Rectangle(30.0, 25.0); helpIcon.setFill(new LinearGradient(0,0,0,1, true, CycleMethod.NO_CYCLE, new Stop[]{ new Stop(0,Color.web("#4977A3")), new Stop(0.5, Color.web("#B0C6DA")), new Stop(1,Color.web("#9CB6CF")),})); helpIcon.setStroke(Color.web("#D0E6FA")); helpIcon.setArcHeight(3.5); helpIcon.setArcWidth(3.5); Text helpText = new Text("?"); helpText.setFont(Font.font("Verdana", FontWeight.BOLD, 18)); helpText.setFill(Color.WHITE); helpText.setStroke(Color.web("#7080A0")); stack.getChildren().addAll(helpIcon, helpText); stack.setAlignment(Pos.CENTER_RIGHT); // 右对齐堆栈中的节点 StackPane.setMargin(helpText, new Insets(0, 10, 0, 0)); // 居中显示"?" hb.getChildren().add(stack); // 将堆栈面板添加到HBox对象 HBox.setHgrow(stack, Priority.ALWAYS); // 给堆栈面板分配任何额外的空间 }
示例1-4中的最后几行代码将堆栈面板添加到示例1-2中创建的HBox
面板,并将其定位在面板的最右边。结果如图1-7所示。
GridPane
GridPane
布局面板使您能够创建一个灵活的行列网格,用于布局节点。节点可以放置在网格的任何单元格中,并根据需要跨越单元格。网格面板适用于创建表单或任何以行列组织的布局。 图1-8显示了一个包含图标、标题、副标题、文本和饼图的网格面板。在此图中,gridLinesVisible
属性设置为显示网格线,显示行、列和行列之间的间隙。此属性对于可视化调试GridPane
布局非常有用。
可以设置间隙属性来管理行和列之间的间距。可以设置填充属性来管理节点与网格面板边缘之间的距离。可以设置垂直和水平对齐属性来管理单元格中各个控件的对齐方式。
示例1-5 创建网格面板
public GridPane addGridPane() { GridPane grid = new GridPane(); grid.setHgap(10); grid.setVgap(10); grid.setPadding(new Insets(0, 10, 0, 10)); // 第2列,第1行的类别 Text category = new Text("销售:"); category.setFont(Font.font("Arial", FontWeight.BOLD, 20)); grid.add(category, 1, 0); // 第3列,第1行的标题 Text chartTitle = new Text("本年度"); chartTitle.setFont(Font.font("Arial", FontWeight.BOLD, 20)); grid.add(chartTitle, 2, 0); // 第2-3列,第2行的副标题 Text chartSubtitle = new Text("商品和服务"); grid.add(chartSubtitle, 1, 1, 2, 1); // 第1列,第1-2行的房子图标 ImageView imageHouse = new ImageView( new Image(LayoutSample.class.getResourceAsStream("graphics/house.png"))); grid.add(imageHouse, 0, 0, 1, 2); // 第1列(底部),第3行的左侧标签 Text goodsPercent = new Text("商品\n80%"); GridPane.setValignment(goodsPercent, VPos.BOTTOM); grid.add(goodsPercent, 0, 2); // 第2-3列,第3行的图表 ImageView imageChart = new ImageView( new Image(LayoutSample.class.getResourceAsStream("graphics/piechart.png"))); grid.add(imageChart, 1, 2, 2, 1); // 第4列(顶部),第3行的右侧标签 Text servicesPercent = new Text("服务\n20%"); GridPane.setValignment(servicesPercent, VPos.TOP); grid.add(servicesPercent, 3, 2); return grid; }
setCenter()
方法在示例1-1中将网格面板添加到边界面板的中心区域。结果如图1-9所示。
当窗口大小调整时,网格面板中的节点根据其布局约束进行调整大小。
FlowPane
FlowPane
布局面板中的节点按顺序布局,并在面板设置的边界处换行。节点可以垂直流动(按列)或水平流动(按行)。垂直流动面板在面板的高度边界处换行。水平流动面板在面板的宽度边界处换行。 图1-10显示了一个使用编号图标的水平流动面板示例。相比之下,在垂直流动面板中,第一列将包含第1至第4页,第二列将包含第5至第8页。
可以设置间隔属性来管理行和列之间的间距。可以设置填充属性来管理节点与面板边缘之间的距离。 示例1-6创建了一个用于一系列页面图标的水平流动面板。
示例1-6 创建流动面板
public FlowPane addFlowPane() { FlowPane flow = new FlowPane(); flow.setPadding(new Insets(5, 0, 5, 0)); flow.setVgap(4); flow.setHgap(4); flow.setPrefWrapLength(170); // preferred width allows for two columns flow.setStyle("-fx-background-color: DAE6F3;"); ImageView pages[] = new ImageView[8]; for (int i=0; i<8; i++) { pages[i] = new ImageView( new Image(LayoutSample.class.getResourceAsStream( "graphics/chart_"+(i+1)+".png"))); flow.getChildren().add(pages[i]); } return flow; }
TilePane
TilePane(瓷砖面板)类似于FlowPane(流式面板)。TilePane
布局面板将所有节点放置在一个网格中,每个单元格或瓷砖的大小相同。节点可以水平排列(按行)或垂直排列(按列)。水平排列在瓷砖面板的宽度边界处换行,垂直排列在高度边界处换行。使用prefColumns
和prefRows
属性来确定瓷砖面板的首选大小。
可以设置间隔属性来管理行和列之间的间距。可以设置填充属性来管理节点与面板边缘之间的距离。
示例1-7创建了一个水平瓷砖面板,产生了与图1-10中显示的相同布局。
示例1-7 创建一个瓷砖面板
TilePane tile = new TilePane(); tile.setPadding(new Insets(5, 0, 5, 0)); tile.setVgap(4); tile.setHgap(4); tile.setPrefColumns(2); tile.setStyle("-fx-background-color: DAE6F3;"); ImageView pages[] = new ImageView[8]; for (int i=0; i<8; i++) { pages[i] = new ImageView( new Image(LayoutSample.class.getResourceAsStream( "graphics/chart_"+(i+1)+".png"))); tile.getChildren().add(pages[i]); }
AnchorPane
AnchorPane
布局容器允许您将节点锚定到面板的顶部、底部、左侧、右侧或中心。当窗口大小改变时,节点保持相对于其锚点的位置不变。节点可以锚定到多个位置,多个节点可以锚定到同一个位置。图1-12显示了一个锚点面板,其中网格面板从GridPane锚定到顶部,一个HBox面板带有两个按钮锚定到底部和右侧。
示例1-8创建了一个锚点面板,其中一个节点锚定到面板的顶部,另一个节点锚定到面板的右下角。在示例1-8中使用了示例1-5中创建的网格。
示例1-8 创建一个锚点面板
public AnchorPane addAnchorPane(GridPane grid) { AnchorPane anchorpane = new AnchorPane(); Button buttonSave = new Button("保存"); Button buttonCancel = new Button("取消"); HBox hb = new HBox(); hb.setPadding(new Insets(0, 10, 10, 10)); hb.setSpacing(10); hb.getChildren().addAll(buttonSave, buttonCancel); anchorpane.getChildren().addAll(grid,hb); // 添加示例1-5中的网格 AnchorPane.setBottomAnchor(hb, 8.0); AnchorPane.setRightAnchor(hb, 5.0); AnchorPane.setTopAnchor(grid, 10.0); return anchorpane; }
以下语句将边界面板的中心区域替换为锚点面板:
border.setCenter(addAnchorPane(addGridPane()));
结果如图1-13所示。
当窗口调整大小时,节点根据其锚点在面板中保持位置不变。如图1-14所示,按钮被锚定在面板底部,随着窗口变小,它们靠近销售信息。