前面介绍了FXML的基本格式及其控制器的用法,算是打通了FXML方式的编码流程。程序界面通常保持固定尺寸,不过有时也允许用户拖曳窗口大小,不拖不打紧,一拖就可能坏事。像之前的登录窗口,没拖的时候界面如下图所示。


现在开始慢慢把窗口拖长,拖到一半停下来,此时登录界面如下图所示。


乍看过去,界面上的各控件大小保持不变,且始终居中显示,没发现什么问题。可是继续拖长窗口,突然之间这些控件乾坤大挪移,用户名区域顶到了第一行,登录按钮跟着顶到了第二行,变化后的界面效果如下图所示。


之所以出现控件排版错乱的问题,是因为该界面的根节点采用了流式窗格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属性,因此各控件之间没能自动分隔开,几乎都粘在一起了,例如:
1、登录类型、用户名、密码三块区域的左侧直接顶到了窗口边缘;
2、用户名输入框、密码输入框、登录按钮三个自上往下紧紧贴着,不留一丝空隙;
似此过于紧凑的界面,令人感觉颇为拘谨,还是留个适当的间隔比较好。虽然VBox不支持hgap与vgap属性,但它另外提供了padding属性组,允许分别指定上、下、左、右四个方向的间距。padding节点挂在哪个VBox或HBox之下,就表示哪个箱子会在内部自动留白,padding对应的xml标签具体写法如下所示:

  <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节点结构变成了以下这般:

<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文件示例如下:

<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>

再次运行测试程序,弹出的登录窗口如下图所示,果然各级控件与周边都隔了一小段距离。


接着在水平方向拉长窗口,拉长之后的窗口界面如下面左图所示。回到初始尺寸,在垂直方向拉高窗口,拉高之后的如下面右图所示。


从上面两张效果图可见,几个箱子和输入框的宽高确实跟随窗口尺寸的变化而变化。


更多Java技术文章参见《Java开发笔记(序)章节目录

Java开发笔记(一百四十五)FXML布局的伸展适配的更多相关文章

  1. Java开发笔记(六十五)集合:HashSet和TreeSet

    对于相同类型的一组数据,虽然Java已经提供了数组加以表达,但是数组的结构实在太简单了,第一它无法直接添加新元素,第二它只能按照线性排列,故而数组用于基本的操作倒还凑合,若要用于复杂的处理就无法胜任了 ...

  2. Java开发笔记(八十五)通过字符流读写文件

    前面介绍了文件的信息获取.管理操作,以及目录下的文件遍历,那么文件内部数据又是怎样读写的呢?这正是本文所要阐述的内容.File工具固然强大,但它并不能直接读写文件,而要借助于其它工具方能开展读写操作. ...

  3. Java开发笔记(二十五)方法的输入参数

    前面通过main方法介绍了方法的定义形式,对于方法的输入参数来说,还有几个值得注意的地方,接下来分别对输入参数的几种用法进行阐述.一个方法可以有输入参数,也可以没有输入参数,倘若无需输入参数,则方法定 ...

  4. Java开发笔记(三十五)字符串格式化

    前面介绍了字符串变量的四种赋值方式,对于简单的赋值来说完全够用了,即便是两个字符串拼接,也只需通过加号把两个目标串连起来即可.但对于复杂的赋值来说就麻烦了,假设现在需要拼接一个很长的字符串,字符串内部 ...

  5. Java开发笔记(四十五)成员属性与成员方法

    前面介绍了许多数据类型,除了基本类型如整型int.双精度型double.布尔型boolean之外,还有高级一些的如包装整型Integer.字符串类型String.本地日期类型LocalDate等等,那 ...

  6. Java开发笔记(七十五)异常的处理:扔出与捕捉

    前面介绍的几种异常(不包含错误),编码的时候没认真看还发现不了,直到程序运行到特定的代码跑不下去了,程序员才会恍然大悟:原来这里的代码逻辑有问题.像这些在运行的时候才暴露出来的异常,又被称作“运行时异 ...

  7. OpenCV开发笔记(六十五):红胖子8分钟带你深入了解ORB特征点(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  8. Java开发笔记(八十二)注解的基本单元——元注解

    Java的注解非但是一种标记,还是一种特殊的类型,并且拥有专门的类型定义.前面介绍的五种内置注解,都可以找到对应的类型定义代码,例如查看注解@Override的源码,发现它的代码定义是下面这样的: @ ...

  9. Java开发笔记(三十二)字符型与整型相互转化

    前面提到字符类型是一种新的变量类型,然而编码实践的过程中却发现,某个具体的字符值居然可以赋值给整型变量!就像下面的例子代码那样,把字符值赋给整型变量,编译器不但没报错,而且还能正常运行! // 字符允 ...

随机推荐

  1. C#常用集合类的实现以及基本操作复杂度

    List 集合类是顺序线性表,Add操作是O(1)或是O(n)的,由于List的容量是动态扩容的,在未扩容之前,其Add操作是O(1),而在需要扩容的时候,会拷贝已存在的那些元素同时添加新的元素,此时 ...

  2. vue Router——基础篇

    vue--Router简介 vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用. vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路 ...

  3. Spring项目配置多数据源

    项目中有用到多数据源,并进行动态切换,使用的是阿里的druid.看网上有一篇大致一样的就偷偷懒 import java.sql.SQLFeatureNotSupportedException; imp ...

  4. jQuery Validate验证框架详解,提交前验证

    现在都用h5表单进行验证了,以下方式仅做回忆 https://www.runoob.com/jquery/jquery-plugin-validate.html <!DOCTYPE HTML P ...

  5. Linux的DNS主从服务器部署

    下面的部署是在Linux的DNS正向解析部署上进行修改的. 如果有什么问题或者错误,可以访问上篇帖子 下面开始有关DNS的服务部署.<DNS主从服务器> 环境描述: 192.168.196 ...

  6. Python 实现两个矩形重合面积

    计算两个矩形的重合面积 import math x1, y1, x2, y2 = input().split(" ") x1, y1, x2, y2=int(x1), int(y1 ...

  7. How to: Create a C/C++ Union by Using Attributes (C#)

    [How to: Create a C/C++ Union by Using Attributes (C#)] 1.you can create what is known as a union in ...

  8. 微软源码站点-C#编程指南

    地址:https://referencesource.microsoft.com/#System.Web/HttpPostedFile.cs 微软的源码可以在这里看. ---------------- ...

  9. error: Libtool library used but 'LIBTOOL' is undefined

    编译时出现: error: Libtool library used but ‘LIBTOOL’ is undefined 参考了一下: http://stackoverflow.com/questi ...

  10. Hadoop 学习资料

    Hadoop 学习资料 网址 官方文档 https://hadoop.apache.org/docs/r1.0.4/cn/index.html 版本文档索引 http://hadoop.apache. ...