diff --git a/source/_posts/miglayout-notes.md b/source/_posts/miglayout-notes.md new file mode 100644 index 0000000..66d3f6a --- /dev/null +++ b/source/_posts/miglayout-notes.md @@ -0,0 +1,276 @@ +--- +title: MigLayout的使用简记 +tags: + - JVM + - Java + - GUI + - Swing + - MigLayout +categories: + - - JVM + - Java +keywords: 'java,swing,miglayout,gui' +mathjax: true +date: 2021-06-22 06:39:30 +--- + +MigLayout是一款用于Swing和SWT、JavaFx的老牌布局管理器。虽然MigLayout已经出现了很长时间了,但是它在进行UI布局的时候,使用方法比较简单,布局说明非常清晰,代码量也不高,是使用Java开发GUI应用时比较推荐的一个布局管理器。MigLayout是一个采用表格方式布局排列的布局管理器,也可以认为它采用的是Grid形式布局,这个布局的特性与CSS 3中的Flex布局的特性相近。在设计MigLayout的布局的时候,可以首先在设计稿上勾画横纵的表格,明确各个组件占用空间的关系,然后再根据MigLayout提供的布局约束描述命令对组件容器进行布局约束定义。 + +要在项目中使用MigLayout,需要根据当前项目所使用的GUI技术来选择使用不同的包。 + +例如使用Maven进行项目构建,可以选择以下依赖项。 + +```xml + + + com.miglayout + miglayout-swing + 11.0 + + + + com.miglayout + miglayout-javafx + 11.0 + + + + com.miglayout + miglayout-swt + 11.0 + +``` +对应的,如果使用Gradle进行项目构建,只需要将以上依赖定义中的GAV坐标提取出来即可。 + +## 布局参数 + +定义布局就必须使用尺寸和单位,MigLayout设计了以下这些尺寸单位供布局定义使用。 + +- `""`,空字符串作为单位时,MigLayout将使用平台默认的单位和像素来计量。 +- `px`,使用屏幕的像素计量,例如`10px`。 +- `%`,使用相对于容器的百分比尺寸,例如`50%`表示在中间。 +- `lp`,使用平台计算得到的逻辑像素,例如`10lp`。 +- `pt`,点,一般为$\frac{1}{72} inch$,例如`10pt`。 +- `mm`,毫米,这个单位会受到屏幕DPI的影响,例如`10mm`。 +- `cm`,厘米,这个单位会受到屏幕DPI的影响,例如`10cm`。 +- `in`,英尺,这个单位会收到屏幕DPI的影响,例如`10in`。 +- `sp`,相对屏幕尺寸的百分比,会根据屏幕的像素数进行计算。这个单位在使用的时候是书写在数字前面的,例如`sp 70`。 +- `al`,视觉边界对齐。取值0到1,`0al`表示左对齐,`0.5al`表示居中,`1al`则表示右对齐。 +- `null`,空值,表示值的缺失与不设定,可缩写为`n`。 + +在设定布局参数的时候,除了可以使用数字与上面这些单位进行搭配以外,还可以使用以下这些关键字来声明一些固定的尺寸,这些尺寸将会由MigLayout自动完成计算。 + +- `related`,声明两个组件或者行列的尺寸是相关的,可以简写为`rel`或者`r`。 +- `unrelated`,声明两个组件或者行列的尺寸是不相关的,可以简写为`unrel`或者`u`。 +- `paragraph`,使用自动确定的段间距,可以简写为`para`或者`p`。 +- `indented`,使用自动确定的缩进,可以简写为`ind`或者`i`。 +- `minimum`,使用行列中出现的**最大**的最小尺寸值,可以简写为`min`。 +- `preferred`,使用行列中出现的**最大**的期望尺寸值,可以简写为`pref`或者`p`。 +- `maximum`,使用行列中出现的**最大**的最大尺寸值,可以简写为`max`。 + +## 布局管理器的创建 + +MigLayout有两种创建布局管理器实例的方法,一种是使用无参构造函数,一种是使用声明默认整体布局的有参构造函数。MigLayout的有参构造函数主要有以下几个。 + +- `MigLayout(LC)`,使用`LC`实例声明MigLayout的布局约束。 +- `MigLayout(LC, AC)`,使用`LC`实例声明MigLayout的布局约束,`AC`实例声明列布局约束。 +- `MigLayout(LC, AC, AC)`,使用`LC`实例声明MigLayout的布局约束,第一个`AC`实例声明列布局约束,第二个`AC`实例声明行布局约束。 +- `MigLayout(String)`,使用字符串描述MigLayout的布局约束。 +- `MigLayout(String, String)`,使用第一个字符串描述MigLayout的布局约束,第二个字符串描述列布局约束。 +- `MigLayout(String, String, String)`,使用第一个字符串描述MigLayout的布局约束,第二个字符串描述列布局约束,第三个字符串描述行布局约束。 + +从以上列表可以看出,MigLayout的构造函数实际上是分为三类的,分别描述整体布局约束、列布局约束和行布局约束。不过虽然MigLayout支持使用`LC`和`AC`两个类来使用强类型约束的形式声明布局约束,但是在大部分情况下,还是推荐优先使用字符串来声明布局约束,因为字符串虽然类型约束很弱,但是描述性和可读性都很强,所需要书写的代码也比较少。 + +!!! note "" + 其实`LC`和`AC`这两个类十分好记,`LC`是Layout Constraint(布局约束)的缩写,`AC`是Axis Constraint(轴向约束)的缩写。在MigLayout中还有一个`CC`类,它是Component Constraint(组件约束)的缩写。 + +### 整体布局约束 + +整体布局约束影响的是整个容器的布局,如果使用无参构造函数实例化MigLayout,将会直接使用在一行内顺序排布的布局方式,而容器中组件的布局也完全由组件自己声明的布局来决定。整体布局中可以使用以下文字描述来对布局约束进行定义。 + +在所有的字符串描述中,多个布局约束描述命令之间使用`,`隔开,例如`wrap 3,fillx`。而使用`LC`类的时候,则只需要选择最终能够返回`LC`实例的方法即可,例如`new LC().wrapAfter(3).fillX()`。 + +!!! note "" + 不仅整体布局约束中的约束描述命令是使用`,`隔开的,轴向布局约束和组件布局约束中的约束描述命令都是使用`,`隔开的。书写时只选择需要的布局约束进行声明即可。 + +| 约束描述命令 | 设定布局功能 | +|---|---| +| `wrap n` | 设定自动换行策略,`n`表示在第几列之后进行换行。 | +| `wrap` | 相当于`wrap 0`,会使容器内的组件按照轴向布局约束设置排列。 | +| `gap x y` | 设定单元格之间的间隙。 | +| `gapx x` | 设定单元格之间横向的间隙。 | +| `gapy y` | 设定单元格之间纵向的间隙。 | +| `nogrid` | 设定布局管理器不使用基于Grid的布局。 | +| `novisualpadding` | 设定不使用可见留白。 | +| `fill` | 组合`fillx`和`filly`的功能。 | +| `fillx` | 设定布局管理器总是尝试获取最大的横向空间。 | +| `filly` | 设定布局管理器总是尝试获取最大的纵向空间。 | +| `insets all` | 同时设定布局四周的留白空间,可以简写为`ins`。 | +| `insets top left bottom right` | 逐一设定布局四周的留白空间。 | +| `flowy` | 设置布局管理器沿纵向排列组件。 | +| `alignx x` | 设置组件在父组件中的横向对齐方式,可以缩写为`ax`。 | +| `aligny y` | 设置组件在父组件中的纵向对齐方式,可以缩写为`ay`。 | +| `align x y` | 组合设置`alignx`和`aligny`,可以缩写为`al`。 | +| `lefttoright` | 设定从左向右布局,可以缩写为`ltr`。 | +| `righttoleft` | 设定从右向左布局,可以缩写为`rtl`。 | +| `toptobottom` | 设定从上向下布局,可以缩写为`ttb`。 | +| `bottomtotop` | 设定从下向上布局,可以缩写为`btt`。 | +| `hidemode n` | 设置组件不可见时的处理方式。 | +| `nocache` | 如果组件的大小与容器的边界关联,那么必须使用此项关闭Panel的缓存。 | +| `width BoundSize` | 同时设定布局的宽度,可以缩写为`w`,参数使用BoundSize描述。 | +| `height BoundSize` | 同时设定布局的高度,可以缩写为`h`,参数使用BoundSize描述。 | +| `wmax n` | 设定布局的最大宽度。 | +| `wmin n` | 设定布局的最小宽度。 | +| `hmax n` | 设定布局的最大高度。 | +| `hmin n` | 设定布局的最小高度。 | + +#### 组件不可见的处理方式 + +命令`hidemode`可以接受以下这几个值作为参数。 + +| 可取值 | 布局处理方式 | +|:---:|---| +| `0` | 默认值,所有不可见的组件依旧会像它们可见时一样占据空间。 | +| `1` | 所有不可见的组件的尺寸将被设置为`0, 0`,但保留其所在单元格周围的间隙。 | +| `2` | 所有不可见的组件的尺寸将被设置为`0, 0`,并且其所在单元格周围的间隙也会被清零。 | +| `3` | 所有不可见的组件不会参与布局,并且不会占据单元格。 | + +#### 对齐命令的参数 + +命令`align`、`alignx`和`aligny`三个命令所接受的参数值主要是以下这几个。 + +| 参数值 | 缩写 | 含义 | +|:---:|:---:|---| +| `top` | `t` | 顶部对齐 | +| `left` | `l` | 左对齐 | +| `bottom` | `b` | 底部对齐 | +| `right` | `r` | 右对齐 | +| `leading` | `lead` | 头部对齐 | +| `trailing` | `trail` | 尾部对齐 | +| `baseline` | `base` | 基线对齐 | + +#### BoundSize描述 + +BoundSize是一组用来描述布局尺寸的参数组合,其中由三个值组成:最小尺寸、期望尺寸和最大尺寸。这是因为在布局尺寸在发生变化的时候,我们通常都需要使用这三个值来对布局和组件的变化进行限定。所以在基本上所有需要使用具体尺寸值的位置,都是使用BoundSize来声明的。BoundSize使用`最小值:期望值:最大值`的格式来声明,例如`30lp:50lp:80lp`。除了可以使用具体数值以外,BoundSize还可以使用`null`、`rel`等需要MigLayout自行计算决定的关键字参数。 + +但是对于BoundSize来说,经常会有以下常用的设置技巧存在,这些也都是对于日常布局的需要而存在的。 + +- 仅设置单个值,例如`10`。这表示仅设置期望值,相当于`null:10:null`。 +- 设置两个值,例如`10:20`。这表示设置最小值和期望值,相当于`10:20:null`。 +- 使用`!`,例如`20!`。这表示最小值、期望值和最大值都使用相同的设置,相当于`20:20:20`。 + +如果需要BoundSize在声明Gap时让Gap能够尽可能的占据所有剩余的空间,可以在BoundSize上附加`push`关键字,例如`gap 10!:push`或者`gap 5:10:20:push`。 + +### 轴向布局约束 + +轴向布局约束是用来定义容器内部每行单元格的的默认布局属性的。轴向布局约束采用`[]`来定义一行内每个单元格的布局属性,两个`[]`之间的表达式定义党员个之间的Gap的属性,所以轴向布局约束的格式就是`[constraint,constraint]gap size[constraint,constraint]`。例如`[10!]10[10:20]`就定义了一行只有两个单元格的布局,这个布局第一个单元格宽度为10,第二个单元格的宽度是20,两个单元格之间的间距是10。其中Gap Size可以使用所有BoundSize表达式来描述。 + +!!! note "" + 如果不需要显式定义间距,直接使用MigLayout的默认间距,那么相邻的`][`就可以被`|`代替。例如`[10][10][10]`就可以简写为`[10|10|10]`。 + +轴向布局约束也有自己的一套约束描述命令,这些约束命令主要是使用在单元格的约束定义上。 + +| 约束描述命令 | 设定布局功能 | +|---|---| +| `sizegroup name` | 给指定的单元格设定尺寸组名称,拥有相同尺寸组名称的单元格将共享相同的尺寸设置。可以简写为`sg` | +| `fill` | 设定单元格中的组件的属性设置为`grow`,使组件将尽可能的占据所有可用横向空间,不会影响单元格空间。 | +| `nogrid` | 不使用单元格布局,而是使用流式布局代替。 | +| `grow n` | 设定尺寸增长的权重,默认权重值是100,已经设定的权重之间,尺寸增长都按照权重的比例进行。 | +| `growprio n` | 设定尺寸的增长优先级,可以在尺寸发生变化时,优先使优先级高的行或者列达到最大尺寸。不影响单元格中的组件。 | +| `shrink n` | 与`grow`相反,设置尺寸缩小时的权重。 | +| `shrinkprio n` | 与`growprio`相反,设置尺寸缩小时的优先级。可以缩写为`shp`。 | +| `align a` | 设置组件在单元格内的对齐方式。可以缩写为`al`。 | +| `gap n` | 单独设置单元格前后的间隙大小。 | +| `gapbefore n` | 单独设置单元格前的间隙大小。 | +| `gapafter n` | 单独设置单元格后的间隙大小。 | + +## 组件排布 + +MigLayout是一个行列布局管理器,所以在默认情况下,MigLayout总是沿着X轴按照组件的添加顺序逐一排列组件。例如以下示例。 + +```java +panel.setLayout(new MigLayout()); +panel.add(new JLabel("Option 1")); +panel.add(new JTextField()); +panel.add(new JLabel("Option 2")); +panel.add(new JTextField()); +``` + +对于每个组件的布局属性是通过`.add()`方法的第二个参数“布局约束”来实现的,比如将组件换到另一行排列。所以上面这个示例可以像下面这样分成两行排列。 + +```java +panel.setLayout(new MigLayout()); +panel.add(new JLabel("Option 1")); +panel.add(new JTextField(), "wrap"); // 布局将在这个组件之后换行 +panel.add(new JLabel("Option 2")); +panel.add(new JTextField()); +``` + +### 组件布局约束 + +组件布局约束也是通过一系列的约束描述命令来完成的,虽然可以使用MigLayout提供的`CC`类来进行强类型形式的定义,但是为了更加简便的描述布局,字符串的形式还是更加简单明了一些。 + +| 约束描述命令 | 设定布局功能 | +|---|---| +| `wrap n` | 设定当前组件是本行最后一个组件,下一个组件将换行放置,`n`表示当前单元格之后需要保留的间隙大小。 | +| `newline n` | 设定在当前组件之前进行换行,当前组件将被放置在新的一行里。`n`表示上一行末尾需要保留的间隙大小。 | +| `push n` | 使组件的大小按照`n`定义的权重比例进行增长,可以单独使用`pushx`和`pushy`来定义横向和纵向。 | +| `skip n` | 跳过指定数量的单元格再放置当前组件。 | +| `span x y` | 在横向和纵向方向上合并指定数量的单元格。 | +| `spanx x` | 合并指定数量的横向单元格。 | +| `spany y` | 合并指定数量的纵向单元格。 | +| `split n` | 将当前单元格分割成指定数量的单元格,之后添加的组件将先被放置在分割出来的单元格里。 | +| `cell x y sx sy` | 设定组件将被放置到的单元格,其中`sx`和`sy`表示指定单元格的合并情况。 | +| `flowx`、`flowy` | 设定单元格中的组件排布方向。 | +| `width BoundSize` | 设定组件的宽,可以简写为`w`。 | +| `height BoundSize` | 设定组件的高,不影响单元格中的组件。可以简写为`h`。 | +| `wmin n`、`wmax n` | 设定组件的最小宽度和最大宽度。 | +| `hmin n`、`hmax n` | 设定组件的最小高度和最大高度。 | +| `grow x y` | 设定组件在指定方向上的尺寸增长权重。 | +| `growx x` | 设定组件在横向上的尺寸增长权重。 | +| `growy y` | 设定组件在纵向上的尺寸增长权重。 | +| `growprio n` | 设定组件尺寸的增长优先级。可以缩写为`gp`。 | +| `growpriox n` | 设定组件横向尺寸的增长的优先级。可以缩写为`gpx`。 | +| `growprioy n` | 设定组件纵向尺寸的增长的优先级。可以缩写为`gpy`。 | +| `shrink n` | 设定组件在尺寸缩小权重。 | +| `shrinkprio x y` | 设定组件尺寸缩小时的优先级。可以缩写为`shp`。 | +| `shrinkpriox n` | 设定组件横向尺寸缩小时的优先级。可以缩写为`shpx`。 | +| `shrinkprioy n` | 设定组件纵向尺寸缩写时的优先级。可以缩写为`shpy`。 | +| `sizegroup name` | 为组件设定一个尺寸组的名称,拥有相同名称尺寸组的组件将具有相同的BoundSize。可以简写为`sg`。 | +| `sizegroupx name` | 为组件设定一个只保存横向尺寸的尺寸组名称。可以简写为`sgx`。 | +| `sizegroupy name` | 为组件设定一个只保存纵向尺寸的尺寸组名称。可以简写为`sgy`。 | +| `endgroup name` | 为组件设定一个终止组名称,拥有相同终止组名称的组件,将会使其右侧和底边保持对齐。可以简写为`eg`。 | +| `endgroupx name` | 为组件设定一个横向的终止组名称。可以简写为`egx`。 | +| `endgroupy name` | 为组件设定一个纵向的终止组名称,可以简写为`egy`。 | +| `gap l r t b` | 为组件设定其所在单元格的外周间隙。只设定一个值时,表示四周都使用相同的BoundSize。另外可以使用`gapleft`、`gaptop`、`gapbottom`、`gapright`、`gapbefore`和`gapafter`来设定具体方向上的间隙大小。 | +| `gapx l r` | 为组件所在的单元格设置横向的外周间隙。只设定一个值时,表示左右两侧都使用相同的BoundSize。 | +| `gapy t b` | 与`gapx`类似,但设置纵向间隙。 | +| `id [grp.] id` | 为组件设置一个ID,这个ID可以用于不同组件之间的相互访问。 | +| `pos x y` | 将组件在容器中使用绝对定位放置。采用绝对定位的组件将不会被放入单元格内。 | +| `pos x y x2 y2` | 将组件在容器中采用绝对定位放置,并且使用`x2`、`y2`设定组件的大小边界。 | +| `x n`、`x2 n`、`y n`、`y2 n` | 设定组件的绝对定位边界。 | +| `dock s` | 将组件泊放在容器的边界上,这个定位能力与BorderLayout类似。在泊放方向不是`center`的时候,`dock`命令可以被省略。泊放方向可取值有`west`、`south`、`east`、`north`和`center`,并且后续的泊放命令将会使之前的泊放被截断,并占据更多的空间。 | +| `pad t l b r` | 在单元格内部,组件的四周设置留白,如果只设置一个值则代表四个方向使用相同的值。 | +| `align x y` | 设置组件在单元格内的对齐,如果只设置一个值则代表在横总两个方向上都使用相同的对齐设置。可以简写为`al`。 | +| `alignx al` | 设置组件在单元格内的横向对齐,可以简写为`ax`。 | +| `aligny al` | 设置组件在单元格内的纵向对齐,可以简写为`ay`。 | +| `external` | 设置禁止组件更改布局的尺寸,布局的尺寸由GUI控制。利用`id`可以关联的获取组件尺寸。 | +| `hidemode n` | 设置组件被隐藏的时候,处理布局变化的方式,参数取值与整体布局约束相同。 | +| `tag n` | 为组件打一个标签。 | + +#### 组件的标签 + +标签可以用于标记和解释组件的用途,并且还可以用来定义组件的排序,但是需要注意的是,这个排序是由系统决定的。在MigLayout中可以使用的标签有一下这些。 + +- `ok`,表示组件是“确认”按钮。 +- `cancel`,表示组件是“取消”按钮。 +- `help`,表示组件是“帮助”按钮,这个按钮通常会被放置在右侧。 +- `help2`,表示组件是“帮助”按钮,这个按钮通常会被放置在左侧。 +- `yes`,表示组件是“是”按钮。 +- `no`,表示组件是“否”按钮。 +- `apply`,表示组件是“应用”按钮。 +- `next`,表示组件是“下一个”按钮。 +- `back`,表示组件是“后退”按钮。 +- `finish`,表示组件是“结束”按钮。 +- `left`,表示按钮组件应该被始终放置在最左边。 +- `right`,表示按钮组件应该始终被放置在最右边。