部分内置布局面板和swing的布局面板功能相同,可以对比学习。实在难以理解,可以多写几个例子自己领悟。

首先上一些布局组件的相关描述:

  1. 边框面板(BorderPane)
    整个被划分为上下左右中的布局,通常上方是菜单栏和工具栏,下方是状态栏,左边是导航面板,右边是附加信息面板,中间是核心工作区域。注意设置顺序,如果窗口的大小比各区域所需空间小,后设置的区域会遮住先设置的区域。

  2. 水平盒子(HBox)
    内部的组件横向排列,可用于顶部导航栏。设置内边距(Padding)属性可以用于管理节点(内部UI组件)到HBox边缘的距离。设置间距(Spacing)属性可以用于管理节点之间的距离。设置样式(Style)属性可以改变背景颜色。

  3. 垂直盒子(VBox)
    纵向排列,可用于左侧菜单。设置内边距(Padding)属性可以管理节点到VBox边缘的距离。设置间距(Spacing)属性可以管理节点之间的距离。设置外边距(Margin)属性可以为单个控件周围增加额外的空间。

  4. 堆栈面板(StackPane)
    将所有的节点放在一个堆栈中进行布局管理,后添加进去的节点会显示在前一个添加进去的节点之上(重叠)。这个布局为将文本(Text)覆盖到一个图形(Shape)或者图像(Image)之上,或者将普通图形相互覆盖来创建更复杂的图形,提供了一个简单的方案。

  5. 网格面板(GridPane)
    设置间隙属性(Gap)用来管理行和列之间的距离。设置内边距属性(Padding)用来管理节点元素和GridPane边缘之间的距离。设置垂直(Vertical)和水平(Horizontal)对齐属性(Alignment)能够控制单元格中的各个控件的对齐方式。属性gridLinesVisible被用来设置显示网格线,这个属性在进行GridPane的可视化调试时非常有用。

  6. 流面板(FlowPane)
    FlowPane布局面板中包含的节点会连续地平铺放置,并且会在边界处自动换行(或者列)。这些节点可以在垂直方向(按列)或水平方向(按行)上平铺。垂直的FlowPane会在高度边界处自动换列,水平的FlowPane会在宽度边界处自动换行。设置间隙属性(Gap)用于管理行和列之间的距离。设置内边距属性(Padding)用于管理节点元素和FlowPane边缘之间的距离。

  7. 磁贴面板(TilePane)
    TilePane布局面板和FlowPane很相似。TilePane将其包含的节点都放在一个网格中,其中每格或者每块磁贴的大小都是一样的。节点可以按水平方向(行)进行排列,或者以垂直方向(列)进行排列。水平排列时会在TilePane的宽度边界处对Tile进行自动换行,垂直排列时会在TilePane的高度边界处对Tile进行自动换列。使用prefColumns和prefRows属性可以设定TilePane的首选大小。
    设置间隙属性(Gap)用来管理行和列之间间距。设置内边距属性(Padding)用来设管理节点元素和TilePane边缘之间的距离。

  8. 锚面板(AnchorPane)
    AnchorPane布局面板可以让你将节点锚定到面板的顶部、底部、左边、右边或者中间位置。当窗体的大小变化时,节点会保持与其锚点之间的相对位置。一个节点可以锚定到一个或者多个位置,并且多个节点可以被锚定到同一个位置。

完整代码示例:

public class LayoutSample extends Application {

    public static void main(String[] args) {
        launch(LayoutSample.class, args);
    }

    @Override
    public void start(Stage stage) {

        // 边框面板,作为最顶层布局
        BorderPane border = new BorderPane();

        HBox hbox = addHBox();
        border.setTop(hbox);//顶部放置一个水平盒子
        border.setLeft(addVBox());//左侧放置垂直盒子

        //添加一个堆栈面板到上方区域的水平盒子中,这个堆栈面板用来实现帮助图标
        addStackPane(hbox);

        border.setRight(addFlowPane());
//        border.setRight(addTilePane());

        //注意设置的顺序,在界面大小不够显示时,后设置的UI组件会遮住先设置的。
//        border.setCenter(addGridPane());
        border.setCenter(addAnchorPane(addGridPane()));

        Scene scene = new Scene(border);
        stage.setScene(scene);
        stage.setTitle("Layout Sample");
        stage.show();
    }

    /*
     * 顶部创建一个带两个按钮的水平盒子
     */
    private 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("Current");
        buttonCurrent.setPrefSize(100, 20);

        Button buttonProjected = new Button("Projected");
        buttonProjected.setPrefSize(100, 20);

        hbox.getChildren().addAll(buttonCurrent, buttonProjected);

        return hbox;
    }

    /*
     * 左侧创建一个垂直盒子,盒子内部是超链接列表
     */
    private VBox addVBox() {

        VBox vbox = new VBox();
        vbox.setPadding(new Insets(10)); //内边距,节点到边缘的距离
        vbox.setSpacing(8);//节点间距

        Text title = new Text("Data");
        title.setFont(Font.font("Arial", FontWeight.BOLD, 14));
        vbox.getChildren().add(title);

        Hyperlink[] options = {
                new Hyperlink("Sales"),
                new Hyperlink("Marketing"),
                new Hyperlink("Distribution"),
                new Hyperlink("Costs")};

        for (int i = 0; i < 4; i++) {
            //为每个节点设置外边距
            VBox.setMargin(options[i], new Insets(0, 0, 0, 8));
            vbox.getChildren().add(options[i]);
        }

        return vbox;
    }

    /**
     * 用堆栈面板创建一个帮助图标,并将其添加到水平盒子的右侧
     *
     * @param hb
     */
    private 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(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.setHgrow(stack, Priority.ALWAYS);// 将HBox水平多余的所有空间都给StackPane,这样前面设置的右对齐就能保证问号按钮在最右边
    }

    /*
     * 中间区域创建一个四列三行的网格布局
     */
    private GridPane addGridPane() {

        GridPane grid = new GridPane();
        grid.setHgap(10);//列间隔
        grid.setVgap(10);//行间隔
        grid.setPadding(new Insets(0, 10, 0, 10));//节点到表格边框的距离

        // 将category节点放在第1行,第2列
        Text category = new Text("Sales:");
        category.setFont(Font.font("Arial", FontWeight.BOLD, 20));
        grid.add(category, 1, 0);

        // 将chartTitle节点放在第1行,第3列
        Text chartTitle = new Text("Current Year");
        chartTitle.setFont(Font.font("Arial", FontWeight.BOLD, 20));
        grid.add(chartTitle, 2, 0);

        // 将chartSubtitle节点放在第2行,占第2和第3列
        Text chartSubtitle = new Text("Goods and Services");
        grid.add(chartSubtitle, 1, 1, 2, 1);

        // 将House图标放在第1列,占第1和第2行
        ImageView imageHouse = new ImageView(
                new Image(LayoutSample.class.getResourceAsStream("/graphics/house.png")));
        grid.add(imageHouse, 0, 0, 1, 2);

        // 将左边的标签goodsPercent放在第3行,第1列,靠下对齐
        Text goodsPercent = new Text("Goods\n80%");
        GridPane.setValignment(goodsPercent, VPos.BOTTOM);
        grid.add(goodsPercent, 0, 2);

        // 将饼图放在第3行,占第2和第3列
        ImageView imageChart = new ImageView(
                new Image(LayoutSample.class.getResourceAsStream("/graphics/piechart.png")));
        grid.add(imageChart, 1, 2, 2, 1);

        // 将右边的标签servicesPercent放在第3行,第4列,靠上对齐
        Text servicesPercent = new Text("Services\n20%");
        GridPane.setValignment(servicesPercent, VPos.TOP);
        grid.add(servicesPercent, 3, 2);

//        grid.setGridLinesVisible(true);//显示网格线
        return grid;
    }

    /**
     * 创建一个流动布局,四行总共八个图标
     */
    private FlowPane addFlowPane() {

        FlowPane flow = new FlowPane();
        flow.setPadding(new Insets(5, 0, 5, 0));//内部组件到面板边框的距离
        flow.setVgap(4);//行间距 垂直间距
        flow.setHgap(4);//列间距 水平间距
        flow.setPrefWrapLength(170); // 预设FlowPane的宽度,使其能够显示两列
        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;
    }

    /**
     * 创建磁贴面板布局,总共四行八个图标。
     */
    private TilePane addTilePane() {

        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]);
        }

        return tile;
    }

    /**
     * 使用网格面板和带按钮的水平盒子创建锚面板
     */
    private AnchorPane addAnchorPane(GridPane grid) {

        AnchorPane anchorpane = new AnchorPane();
        //创建按钮
        Button buttonSave = new Button("Save");
        Button buttonCancel = new Button("Cancel");

        //按钮放在水平盒子内
        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);

        //将按钮定位到右下角,将网格定位到顶部
        AnchorPane.setBottomAnchor(hb, 8.0);
        AnchorPane.setRightAnchor(hb, 5.0);
        AnchorPane.setTopAnchor(grid, 10.0);

        return anchorpane;
    }
}

Q.E.D.


擅长前端的Java程序员