前面介紹了FXML的基本格式及其控制器的用法,算是打通了FXML方式的編碼流程。程序界面一般保持固定尺寸,不過有時也容許用戶拖曳窗口大小,不拖不打緊,一拖就可能壞事。像以前的登陸窗口,沒拖的時候界面以下圖所示。html
如今開始慢慢把窗口拖長,拖到一半停下來,此時登陸界面以下圖所示。java
乍看過去,界面上的各控件大小保持不變,且始終居中顯示,沒發現什麼問題。但是繼續拖長窗口,忽然之間這些控件乾坤大挪移,用戶名區域頂到了第一行,登陸按鈕跟着頂到了第二行,變化後的界面效果以下圖所示。佈局
之因此出現控件排版錯亂的問題,是由於該界面的根節點採用了流式窗格FlowPane。所謂流式,指的是從左到右排列,假若沒排滿一行,就跟在當前行後面;只有排滿了一行,纔會另起一行繼續排。剛剛拖拉窗口的時候,拖得太長了,致使窗口的寬度可以容納登陸類型與用戶名兩個區域,結果兩塊區域便擠到同一行了。顯然這不是指望的界面佈局,至少控件要老老實實呆在本身的位置,不可越雷池一步。
若想避免流式窗格排版飄忽的問題,可使用垂直箱子VBox替換流式窗格,垂直箱子規定它的每一個直接下級都佔用一行,絕對不會產生兩個直接下級擠在同一行的現象。因而修改原來的fxml文件,把根節點FlowPane換成VBox,對應的xml標籤變爲如下格式:測試
<VBox fx:controller="com.javafx.fxml.LoginController" xmlns:fx="http://javafx.com/fxml" alignment="center"> <!-- 這是xml註釋標記。中間省略登陸窗口的各控件標籤 --> </VBox>
fxml文件修改完畢,從新運行測試程序,彈出的登陸窗口以下圖所示。編碼
如今無論怎樣拉長窗口,各區域都留在當前行,不再會亂跑了。然而採用VBox的界面很不協調,原因在於VBox不支持hgap與vgap屬性,所以各控件之間沒能自動分隔開,幾乎都粘在一塊兒了,例如:
一、登陸類型、用戶名、密碼三塊區域的左側直接頂到了窗口邊緣;
二、用戶名輸入框、密碼輸入框、登陸按鈕三個自上往下牢牢貼着,不留一絲空隙;
似此過於緊湊的界面,使人感受頗爲拘謹,仍是留個適當的間隔比較好。雖然VBox不支持hgap與vgap屬性,但它另外提供了padding屬性組,容許分別指定上、下、左、右四個方向的間距。padding節點掛在哪一個VBox或HBox之下,就表示哪一個箱子會在內部自動留白,padding對應的xml標籤具體寫法以下所示:code
<padding> <Insets top="10.0" bottom="10.0" left="10.0" right="10.0"/> </padding>
上述的padding節點例子,定義了在上、下、左、右四個方向各留出10個像素的空白間距。考慮到VBox和HBox下面可能掛着好幾個子控件,爲了更好地將這些子控件跟padding區分開,fxml又給VBox和HBox引入了children子節點,凡是下級控件通通放到children節點之下,而padding節點專門放置四個方向的間隔距離。如此一來,形態完整的VBox節點結構變成了如下這般:xml
<VBox fx:controller="com.javafx.fxml.LoginController" xmlns:fx="http://javafx.com/fxml" alignment="center"> <children> <!-- 這是xml註釋標記。中間省略VBox的下級控件列表 --> </children> <padding> <Insets top="10.0" bottom="10.0" left="10.0" right="10.0"/> </padding> </VBox>
由上面的xml樣例能夠看到,改進以後的VBox標籤變得井井有條、結構清晰,大大加強了它的可讀性。
除此以外,fxml還爲VBox和HBox提供了自動伸展功能,也就是說,隨着窗口尺寸的增大,VBox和HBox的寬高也會隨之增大。其中水平方向的寬度自適應,由屬性HBox.hgrow控制,其值爲ALWAYS時表示當前箱子的寬度跟隨上級變化;垂直方向的寬度自適應則由屬性VBox.vgrow控制,其值爲ALWAYS時表示當前箱子的高度跟隨上級變化。尤爲須要注意的是,除了VBox和HBox這兩個箱子支持自動伸展之外,只有幾個輸入框控件支持自動伸展,其中TextField與PasswordField只支持水平方向上的自動伸展,而TextArea同時支持水平與垂直兩個方向的自動伸展。
利用fxml的幾個新節點和新屬性改造原先的登陸界面,一方面,整個登陸界面在窗口四周邊緣均留白,各行之間也留出一條縫隙;另外一方面,令用戶名輸入框和密碼輸入框支持水平伸展,令用戶名區域和密碼區域支持垂直伸展。這麼改造一番以後的fxml文件示例以下:htm
<VBox fx:controller="com.javafx.fxml.LoginController" xmlns:fx="http://javafx.com/fxml" alignment="center"> <children> <HBox fx:id="hbType" prefWidth="400" prefHeight="40"> <children> <Label fx:id="labelType" prefWidth="120" prefHeight="40" text="登陸類型:" /> <fx:define> <ToggleGroup fx:id="tgType" /> </fx:define> <RadioButton fx:id="rbPassword" prefWidth="140" prefHeight="40" toggleGroup="$tgType" text="密碼登陸" selected="true" /> <RadioButton fx:id="rbVerifycode" prefWidth="140" prefHeight="40" toggleGroup="$tgType" text="驗證碼登陸" /> </children> <padding> <Insets top="0.0" bottom="10.0" left="0.0" right="0.0"/> </padding> </HBox> <HBox fx:id="hbUser" prefWidth="400" prefHeight="40" VBox.vgrow="ALWAYS"> <children> <Label fx:id="labelUser" prefWidth="120" prefHeight="40" text="用戶名:" /> <TextField fx:id="fieldUser" prefWidth="280" prefHeight="40" HBox.hgrow="ALWAYS" /> </children> <padding> <Insets top="0.0" bottom="10.0" left="0.0" right="0.0"/> </padding> </HBox> <HBox fx:id="hbPassword" prefWidth="400" prefHeight="40" VBox.vgrow="ALWAYS"> <children> <Label fx:id="labelPassword" prefWidth="120" prefHeight="40" text="密 碼:" /> <PasswordField fx:id="fieldPassword" prefWidth="280" prefHeight="40" HBox.hgrow="ALWAYS" /> </children> <padding> <Insets top="0.0" bottom="10.0" left="0.0" right="0.0"/> </padding> </HBox> <Button fx:id="btnLogin" prefWidth="400" prefHeight="40" text="登 錄" /> <Label fx:id="labelLoginResult" prefWidth="400" prefHeight="40" text="這裏顯示登陸結果" /> </children> <padding> <Insets top="10.0" bottom="10.0" left="10.0" right="10.0"/> </padding> </VBox>
再次運行測試程序,彈出的登陸窗口以下圖所示,果真各級控件與周邊都隔了一小段距離。blog
接着在水平方向拉長窗口,拉長以後的窗口界面以下面左圖所示。回到初始尺寸,在垂直方向拉高窗口,拉高以後的以下面右圖所示。開發
從上面兩張效果圖可見,幾個箱子和輸入框的寬高確實跟隨窗口尺寸的變化而變化。
更多Java技術文章參見《Java開發筆記(序)章節目錄》