控件布局
控件布局分为三种
- 拖动布局
- 代码布局
- 布局器布局
1.拖动布局
1.1 实现方法
我们的控件都可以直接鼠标拖动到form里,可以自行调整位置
但是有时候鼠标拖动也不是很准确
我们可以按住ctrl,鼠标依次点击需要布局的控件,然后编辑器上方会有一些图标亮起来
或者鼠标框选一片区域,被框选中的控件也可以进行此操作

上方form里可以看到有一个文本框,两个按钮,我们已经将这三个控件选中,若想让这三个空间水平对齐,可以点击如下按钮

之后可以看到这三个控件水平在一条线上了

其次,当我们点击某个空间聚焦时,也可以点击编辑器菜单的格式栏,来设置间距、大小、对齐

1.2 实现原理
观察代码我们可以发现,上面方法是修改了空间的Location和size
this.button1.Location = new System.Drawing.Point(399, 14);
this.button1.Size = new System.Drawing.Size(75, 23);1.3 缺点
我们使用编辑器手动拖动控件,创建以下布局

当我们调整窗口的大小时,发现控件没有随着窗口改变而改变,也就是没有自适应

2.手动布局
用代码计算每个空间的位置
2.1 窗口的尺寸
在手动布局之前,我们需要了解窗口的尺寸,窗口的尺寸分为窗口大小和客户区大小
- 窗口大小:整个窗口,包含标题栏和边框,通过
Form的Size属性获取 - 客户区大小:仅客户区,不包含标题栏和边框,通过
Form的ClientSize属性获取
int w=this.Size.Width; // 窗口区宽度
int h=this.Size.Height; // 窗口区高度
int cw=this.ClientSize.Width; // 客户区宽度
int ch=this.ClientSize.Height; // 客户区高度
2.2 实现方法
重写OnLayout方法
override void OnLayout(LayoutEventArgs levent){
// ...
}当窗口大小改变时,会自动调用这个方法重新布局
protected override void OnLayout(LayoutEventArgs e) {
base.OnLayout(e); // 先调用父类OnLayout方法
int cw=this.ClientSize.Width;
int ch=this.ClientSize.Height;
this.textBox1.AutoSize = false; // 使文本框大小可调节
this.textBox1.Location=new System.Drawing.Point(4, 4);
this.textBox1.Size=new System.Drawing.Size(cw-100, 30);
this.button1.Location = new System.Drawing.Point(cw - 80-4, 4);
this.button1.Size = new System.Drawing.Size(80, 30);
this.pictureBox1.Location = new System.Drawing.Point(4, 40);
this.pictureBox1.Size = new System.Drawing.Size(cw-8, ch - 40 - 4);
}TIP
需要给TextBox的AutoSize属性设置为false,TextBox控件的宽高才可调节
this.textBox1.AutoSize = false;
2.3 Anchor
Anchor可以设置控件与父窗口的边距是否保持不变
Anchor可以设置四个方向,分别是上下左右,这几个方向也可以结合
- 上:
System.Windows.Forms.AnchorStyles.Top - 下:
System.Windows.Forms.AnchorStyles.Bottom - 左:
System.Windows.Forms.AnchorStyles.Left - 右:
System.Windows.Forms.AnchorStyles.Right
给控件设置单个方向的锚点时,只需如下写法
this.button1.Anchor = System.Windows.Forms.AnchorStyles.Top;但是给控件设置多个方向锚点时,需要如下写法
this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));手写太麻烦,还是从工具栏点击比较好
选中空间,在工具箱查找Anchor属性,下拉框打开之后,发现四边都有一个矩形,点击几个添加/取消此方向的锚点

锚点有以下常用的方法
锚定与左下角:左下锚点

锚定与右下角:右下锚点

锚定与上边缘、水平拉伸:左右上锚点

锚定与上边缘、水平居中:水平居中、上锚点

拉伸:上下左右锚点

居中与窗口中央:水平居中、垂直居中、锚点无

2.4 Dock
Dock可以将控件停靠在一侧或中央
选中空间后在属性栏找到Dock属性,可以看到有几块区域可以点击,点哪个方向,该控件就会停靠在哪个位置

停靠后,控件会随着窗口的变化而拉伸
我们创建了三个Panel空间,分别停靠在上、左、中央,这类似一个后台管理的布局,如下所示

代码实现如图所示
this.panel1.Dock = System.Windows.Forms.DockStyle.Top; // 停靠在 上 端
this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom; // 停靠在 下 端
this.panel1.Dock = System.Windows.Forms.DockStyle.Left; // 停靠在 左 端
this.panel1.Dock = System.Windows.Forms.DockStyle.Right; // 停靠在 右 端
this.panel1.Dock = System.Windows.Forms.DockStyle.None; // 无停靠WARNING
Anchor和Dock是冲突的,不可以同时使用
若使用Dock布局,最终的布局效果依赖于空间添加的顺序
比如:在一个Panel里像如下两种情况添加两个按钮
第一个Dock设置Left,第二个设置Fill,会是如下情况

第一个Dock设置Fill,第二个设置Left,会是如下情况

可以看到,第二种情况,第二个按钮会把第一个按钮的左边挡住
3.布局器
一些具有布局功能的控件,会有一个LayoutEngine属性,该属性用于负责子控件的布局,叫做布局器
一个Form或Panel都自带一个布局器
当窗口改变大小时,由窗口的布局器来负责调整布局
3.1 自定义布局器
自定义布局器使用步骤:
1.编辑器菜单栏=》工具=》选项=》Windows窗口设计器=》常规=》自动填充工具箱=True

2.添加自定义Panel或Control类
我们创建一个自动水平拉伸的布局空间
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.Layout;
namespace 布局器
{
public partial class CustomPanel:Panel
{
private readonly LayoutEngine layoutEngine=new CustomLayoutEngine();
public override LayoutEngine LayoutEngine
{
get
{
return layoutEngine;
}
}
}
class CustomLayoutEngine : LayoutEngine
{
public override bool Layout(object container, LayoutEventArgs layoutEventArgs)
{
CustomPanel parent = (CustomPanel)container;
int w=parent.Width;
int h=parent.Height;
int x=parent.Padding.Left;
int y=parent.Padding.Top;
w-=(x+parent.Padding.Right);
h-=(y+parent.Padding.Bottom);
int gap = 2;
foreach (Control control in parent.Controls) {
control.Location=new System.Drawing.Point(x, y);
control.Size=new System.Drawing.Size(w, control.PreferredSize.Height);
y += control.Size.Height;
y += gap;
}
return false;
}
}
}3.编辑器菜单栏=》生成=》重新生成解决方案

4.关闭Form1.cs重新打开,观察工具箱,发现多了一个我们自定义的布局空间

把此布局空间拖到窗口中,再往这个布局空间中拖进几个其他空间,我们发现里面的空间会被自动拉伸

3.2 FlowLayoutPanel
FlowLayoutPanel是winform自带的一个面板,里面实现了流式布局器,在工具栏的容器中可以找到

然后我们把一些控件拖进这个布局器,发现这些空间都是从左到右依次排列,若剩余空间不足,则另起一行,而且当我们拖动改变这个布局器的大小时,布局也会随着变化

布局器也可以设置Anchor和Dock属性
3.3 TableLayoutPanel
TableLayoutPanel是winform自带的一个面板,里面有一个表格布局器,在工具栏的容器中可以找到

拖进来之后可以看到,这是一个默认两行两列的表格

3.3.1 表格操作
右键任意单元格,或者属性栏中找到Rows和Columns属性,可以设置当前行/列的属性
右键任意单元格

属性栏中找到Rows和Columns属性

点击属性值的三个点
...,在弹出的窗口中设置行/列属性
分别有如下操作
- 添加行/列
- 添加行:在当前表格末尾(最底部)添加一行
- 添加行:在当前表格末尾(最右边)添加一列
- 在当前单元格插入
- 插入行:在被选中行上方插入一行
- 插入列:在被选中列左边插入一行
- 删除行/列:删除当前行/列
3.3.2 尺寸模式
右键任意单元格,可以设置当前单元格横向/竖向的SizeMode,也就是尺寸模式,分别有以下三种模式
- 绝对:固定的宽度/高度
- 百分比:去除其他非百分比的单元格后,剩余空间的占比
- 自动调整大小:根据单元格内容自动调整
