说道GUI编程一定要谈到布局,JavaFX内置了大量的布局控件提供给我们使用。其实,JavaFX的布局控件和界面元素控件都是继承自javafx.scene.layout.Region类。我们这里只看布局控件类。布局控件我们在界面上一般是看不到的,它一个容器用于放置其它可视的界面元素控件。(JavaFX在线API文档:JavaFX8 API Online)
JavaFX布局控件的类图如下:
下面简单说说一些常用控件类的用法。这里我们使用SceneBuilder进行界面的设计,SceneBuilder可以在Gluon下载。SceneBuilder的界面如下,我们可以简单使用拖拽的方法进行界面设计。
Pane是其它布局控件类的父类,我们可以将Pane看成一个绝对布局控件,当我们将某个控件放置在Pane当中的时候,我们需要指定它的位置坐标(layoutX和layoutY)。当我们将一个控件拖拽到Pane中的时候,会自动生成layoutX和layoutY坐标。如图是使用Pane为父容器设计的一个简单界面:
FXML代码如下:
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="350.0" prefWidth="500.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button layoutX="318.0" layoutY="210.0" mnemonicParsing="false" text="登录" />
<Label layoutX="136.0" layoutY="104.0" text="用户名:" />
<Label layoutX="136.0" layoutY="162.0" text="密 码:" />
<TextField layoutX="212.0" layoutY="100.0" />
<PasswordField layoutX="212.0" layoutY="158.0" />
children>
Pane>
BorderPane将界面分割上上下左右中5部分,我们可以将控件放置在其中。常见的一个用例场景就是,软件主界面的上面是菜单栏和工具条,左边和右边可能是文档或者内容列表或者常用的工具集合,然后中间是主要内容显示区,下面是状态栏。
在SceneBuilder中我们将一个控件拖拽到BorderPane的时候,会有上下左右中的区域显示。
我们在这5个区域放置5个标签,如下图:
FXML代码如下:
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<top>
<Label style="-fx-font-family: Arial; -fx-font-size: 20px;" text="上" BorderPane.alignment="CENTER" />
top>
<left>
<Label style="-fx-font-family: Arial; -fx-font-size: 20px;" text="左" BorderPane.alignment="CENTER" />
left>
<right>
<Label style="-fx-font-family: Arial; -fx-font-size: 20px;" text="右" BorderPane.alignment="CENTER" />
right>
<center>
<Label style="-fx-font-family: Arial; -fx-font-size: 20px;" text="中" BorderPane.alignment="CENTER" />
center>
<bottom>
<Label style="-fx-font-family: Arial; -fx-font-size: 20px;" text="下" BorderPane.alignment="CENTER" />
bottom>
BorderPane>
该FXML代码中我们设置了字体,让显示更大一些。在后面我们将使用CSS样式进行字体颜色等样式的设置。
HBox可以水平排列控件,不换行。如图:
FXML代码如下:
<HBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="50.0" prefWidth="500.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="100.0" text="Button1" />
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="100.0" text="Button2" />
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="100.0" text="Button3" />
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="100.0" text="Button4" />
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="100.0" text="Button5" />
children>
HBox>
VBox类似的,垂直排列控件,不换列。如图:
FXML代码如下:
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="300.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="100.0" text="Button1" />
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="100.0" text="Button2" />
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="100.0" text="Button3" />
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="100.0" text="Button4" />
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="100.0" text="Button5" />
children>
VBox>
FlowPane感觉像HBox和VBox的综合体,FlowPane可以设置一个方向水平或者垂直。默认方向为水平,那么放入FlowPane中的控件会先水平排列,如果第一行满了以后进入下一行继续水平排列。垂直方向类似的,先垂直排列,如果第一列满了以后进入第二列继续垂直排列。如图:
可以看到水平方向上满了以后,进入到下一行排列。
FXML代码如下:
<FlowPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button mnemonicParsing="false" prefHeight="149.0" prefWidth="55.0" text="Button" />
<Button mnemonicParsing="false" text="Button" />
<Button mnemonicParsing="false" prefHeight="125.0" prefWidth="100.0" text="Button" />
<Button mnemonicParsing="false" prefHeight="71.0" prefWidth="55.0" text="Button" />
<Button mnemonicParsing="false" prefHeight="97.0" prefWidth="102.0" text="Button" />
<Button mnemonicParsing="false" prefHeight="112.0" prefWidth="213.0" text="Button" />
<Button mnemonicParsing="false" prefHeight="52.0" prefWidth="104.0" text="Button" />
children>
FlowPane>
GridPane有点像HTML中的Table布局,属于比较灵活的布局方式。默认情况下,控件均匀分布在Grid或者说Table中。但是我们可以指定一个控件所占的行列,让其跨行和列分布。当我们将一个元素拖拽到GridPane中的时候可以看到SceneBuilder为我们虚拟除了行和列的分割线:
最后设计的界面如图所示:
FXML代码如下:
<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
rowConstraints>
<children>
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="80.0" text="Button" />
<Button mnemonicParsing="false" prefHeight="180.0" prefWidth="55.0" text="Button" GridPane.columnIndex="1" GridPane.rowSpan="2" />
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="80.0" text="Button" GridPane.rowIndex="1" />
<Button mnemonicParsing="false" prefHeight="50.0" prefWidth="521.0" text="Button" GridPane.columnSpan="2" GridPane.rowIndex="2" />
children>
GridPane>
AnchorPane可以设置一个控件的Anchor位置,感觉NET的GUI控件中最早提供这种控件的。比如说我们要将一个Button放置在左下角,离右边100px,离下边100px的位置,我们便可以使用AnchorPane控件。当窗口放大缩小的时候,该Button始终在左下角离右边100px,离下边100px的位置。通俗地说,AnchorPane可以将控件锚定到布局面板的某个位置。
在SceneBuilder中我们可以很容易在右边的属性面板中设置锚定的方位和距离:
比如我们在左上角和右下角放置两个Button,如图:
当我们调整窗体的大小的时候,锚定位置是不会变的。
生成的FXML代码如下:
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button layoutX="174.0" layoutY="177.0" mnemonicParsing="false" text="右下" AnchorPane.bottomAnchor="100.0" AnchorPane.rightAnchor="100.0" />
<Button layoutX="106.0" layoutY="63.0" mnemonicParsing="false" text="左上" AnchorPane.leftAnchor="100.0" AnchorPane.topAnchor="100.0" />
children>
AnchorPane>
ScrollPane顾名思义就是可以显示滚动条的容器控件了。
我们在ScrollPane中放置一个TextArea文本域控件,并且设置TextArea的大小大于ScrollPane的大小,这样就可以显示出水平和垂直滚动条了。如下图:
FXML代码如下:
<ScrollPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<content>
<TextArea prefHeight="600.0" prefWidth="500.0" />
content>
ScrollPane>
这一节我们说了一些常见的JavaFX布局容器或者叫布局控件,当然JavaFX还提供了很多其它的布局控件。不过使用这一节常用的布局就可以设计出常见的GUI界面了。
在我们用SceneBuilder设计界面的时候,自动生成的FXML文件中的实体元素和属性是和JavaFX中的类和属性是对应的,我们可以通过FXML了解对应类的一些属性和方法。