图形界面编程(五) 布局容器类(2)
点击打开链接
3 布局中的空白区域
在.net Framework中,每个控件和其所处的容器以及容器内控件之间,都存在一个可以调整的空白区域,这个空白区域纯粹是为了布局的美观性而存在的。
容器和容器内控件之间的空白称为容器的Padding属性,容器内控件之间的空白称为控件的Margin属性。看一下示意图:
图1 Padding和Margin示意图
很容易理解,蓝色箭头表示的四个空白位置为窗体容器的Padding属性;黄色箭头表示的四个空白位置为按钮控件的Margin属性。
注意:一个控件离其所在容器四周的距离,是容器的Padding属性和该控件的Margin属性之和。例如图中的按钮0,它和Form容器的左边的距离就是Form容器的Padding属性和按钮0的Margin属性之和。
Padding属性和Margin属性的值都是一个Padding类的对象,Padding类为值类型对象,具有四个整型类型属性:Left,Top,Right,Bottom,分别表左上右下四个方向的空白大小。Padding类还有一个特殊的整型类型属性:All,当Left,Top,Right,Bottom属性值相同时,All属性是Left,Top,Right,Bottom其中一个的值,否则All属性值为-1。即当Padding对象的All属性为-1时,表示其Left,Top,Right,Bottom属性值不同,当All属性值为正整数时,表示Left,Top,Right,Bottom值相同,等于All的值。
可以猜想,Padding类大致如下:
Padding.cs
[c-sharp] view plain copy
- public struct Padding {
- // 字段
- private bool all;
- private int top;
- private int left;
- private int right;
- private int bottom;
- // 静态只读字段, 表示一个四周为0的Padding对象
- public static readonly Padding Empty = new Padding(0);
- ///
- /// 构造器, 通过设置All属性, 设置上下左右四个属性值
- ///
- public Padding(int all) {
- // 设置all标志为true
- this.all = true;
- // 设置上下左右四个字段, 值相同
- this.top = this.left = this.right = this.bottom = all;
- }
- ///
- /// 设置上下左右四个属性值
- ///
- public Padding(int left, int top, int right, int bottom) {
- // 设置上下左右四个属性值
- this.top = top;
- this.left = left;
- this.right = right;
- this.bottom = bottom;
- // 根据上下左右四个属性值是否相同设置all标志
- this.all = (this.top == this.left) &&
- (this.left == this.right) &&
- (this.right == this.bottom) &&
- (this.bottom == this.top);
- }
- ///
- /// All属性, 如果上下左右属性值相同, 则返回其中一个值, 否则返回-1
- ///
- public int All {
- get {
- // 根据all标志是否为true, 决定返回上下左右任意值或-1
- return this.all ? this.top : -1;
- }
- set {
- // 设置all标志为true
- this.all = true;
- // 设置上下左右四个字段, 值相同
- this.top = this.left = this.right = this.bottom = value;
- }
- }
- ///
- /// 设置或获取底部空白
- ///
- public int Bottom {
- get {
- return this.bottom;
- }
- set {
- this.bottom = value;
- // 根据上下左右四个属性值是否相同设置all标志
- this.all = (this.top == this.left) &&
- (this.left == this.right) &&
- (this.right == this.bottom) &&
- (this.bottom == this.top);
- }
- }
- ///
- /// 设置或获取左边空白
- ///
- public int Left {
- get {
- return this.left;
- }
- set {
- this.left = value;
- this.all = (this.top == this.left) &&
- (this.left == this.right) &&
- (this.right == this.bottom) &&
- (this.bottom == this.top);
- }
- }
- ///
- /// 设置或获取右边空白
- ///
- public int Right {
- get {
- return this.right;
- }
- set {
- this.right = value;
- this.all = (this.top == this.left) &&
- (this.left == this.right) &&
- (this.right == this.bottom) &&
- (this.bottom == this.top);
- }
- }
- ///
- /// 设置或获取顶部空白
- ///
- public int Top {
- get {
- return this.top;
- }
- set {
- this.top = value;
- this.all = (this.top == this.left) &&
- (this.left == this.right) &&
- (this.right == this.bottom) &&
- (this.bottom == this.top);
- }
- }
- ///
- /// 获取水平空白总和
- ///
- public int Horizontal {
- get {
- return this.right + this.left;
- }
- }
- ///
- /// 获取垂直空白总和
- ///
- public int Vertical {
- get {
- return this.top + this.bottom;
- }
- }
- ///
- /// 获取以空白值为属性的Size类型对象
- ///
- public Size Size {
- get {
- return new Size(this.Horizontal, this.Vertical);
- }
- }
- ///
- /// 静态方法, 获取两个Padding对象的和
- /// (即将两个对象的上下左右属性各自相加后得到的Padding对象)
- ///
- public static Padding Add(Padding p1, Padding p2) {
- // 调用重载的+运算符
- return (p1 + p2);
- }
- ///
- /// 静态方法, 获取两个Padding对象的差
- /// (即将两个对象的上下左右属性各自想减后得到的Padding对象)
- ///
- public static Padding Subtract(Padding p1, Padding p2) {
- // 调用重载的-运算符
- return (p1 - p2);
- }
- ///
- /// 覆盖对象的比较方法
- ///
- public override bool Equals(object other) {
- // 判断对象的类型后调用对象重载的==运算符
- return ((other is Padding) && (((Padding)other) == this));
- }
- ///
- /// 重载+运算符, 表示两个Padding类型对象相加
- ///
- public static Padding operator +(Padding p1, Padding p2) {
- // 将两个对象的上下左右属性各自相加后得到的新的Padding对象
- return new Padding(p1.Left + p2.Left,
- p1.Top + p2.Top,
- p1.Right + p2.Right,
- p1.Bottom + p2.Bottom);
- }
- ///
- /// 重载-运算符, 表示两个Padding类型对象相减
- ///
- public static Padding operator -(Padding p1, Padding p2) {
- // 将两个对象的上下左右属性各自相减后得到的新的Padding对象
- return new Padding(p1.Left - p2.Left,
- p1.Top - p2.Top,
- p1.Right - p2.Right,
- p1.Bottom - p2.Bottom);
- }
- ///
- /// 重载==运算符
- ///
- public static bool operator ==(Padding p1, Padding p2) {
- if (p1.all && p2.all) { // 如果p1和p2的all字段都为true, 则比较它们的Top属性
- return p1.Top == p2.Top;
- } else { // 否则将它们对应属性一一比较
- return (p1.Left == p2.Left) &&
- (p1.Top == p2.Top) &&
- (p1.Right == p2.Right) &&
- (p1.Bottom == p2.Bottom);
- }
- }
- ///
- /// 重载!=运算符
- ///
- public static bool operator !=(Padding p1, Padding p2) {
- return !(p1 == p2);
- }
- ///
- /// 覆盖GetHashCode方法(因为覆盖了Equals方法)
- ///
- public override int GetHashCode() {
- return this.left ^ this.Right ^ this.Top ^ this.Bottom;
- }
- ///
- /// 覆盖ToString方法, 返回字符串表示
- ///
- public override string ToString() {
- return string.Format(“{ Left={0}, Top={1}, Right={2}, Bottom={3} }“,
- this.Left, this.Top, this.Right, this.Bottom);
- }
- }
通过Padding类的源码(猜想,非官方源码),可以了解Padding五个属性的工作方式,顺便复习一下值类型构造、比较、Empty字段以及运算符重载的知识。
4 流式布局
我们已经了解,控件都具备Dock方位布局能力,可以按照“上下左右中”五个方位将自身锚定在容器上进行布局。但我们也看到,如果要让容器内的控件进行其它形式的布局(例如上一节中控件成行列布局),则一般需要在容器的Resize事件处理方法内,为容器内的所有控件使用算法进行布局。其复杂度和代码量都不好控制。
除非有特殊需要,一般情况下我们尽量不要自己书写大段的控件布局代码,这些代码很不经济。.net Framework提供了若干个专门用来负责布局控件的容器,使用起来非常方便。
FlowLayoutPanel称为流式布局面板容器,它的作用是将容器内控件按照从左到右(或从右到左)以及从上到下(或从下到上)的顺序排列布局。几点重要属性:
- FlowDirection属性:FlowDirection枚举类型。表示容器内控件布局方向。分别为:LeftToRight(从左到右),TopDown(从上到下),RightToLeft(从右到左),BottomUp(从下到上)四个枚举项。
- WrapContents属性:bool类型。表示是否为容器内控件布局自动换行。对于属性值为true,当控件超出容器范围,则将控件自动排列到下一行;对于false,则忽略超出部分的显示。
- AutoScroll属性:bool类型。表示当WrapContents属性为false时,当控件超出容器范围时,容器是否显示一个滚动条。
好了,该容器使用起来很简单,我们通过实例来说明:
界面显示效果图如下:
代码如下:
Program.cs
[c-sharp] view plain copy
- using System;
- using System.Drawing;
- using System.Windows.Forms;
- namespace Edu.Study.Graphics.FlowLayout {
- ///
- /// 窗体类
- ///
- class MyForm : Form {
- /************ 流式布局面板 ************/
- // 顶部流式布局面板
- private FlowLayoutPanel topPane;
- // 底部流式布局面板
- private FlowLayoutPanel bottomPane;
- /************ 文字标签 ************/
- // 布局方向标签
- private Label flowDirectionComboBoxLabel;
- // 容器Padding尺寸标签
- private Label panddingTrackBarLabel;
- // 控件Margin尺寸标签
- private Label marginTrackBarLabel;
- /************ 组合下拉列表框 ************/
- // 选择流式布局方向的下拉列表框
- private ComboBox flowDirectionComboBox;
- /************ 复选框 ************/
- // 布局容器是否自动换行复选框
- private CheckBox wrapCheckBox;
- // 容器是否自动换行复选框
- private CheckBox autoScrollCheckBox;
- /************ 数字调节块 ************/
- // 设置容器Padding属性的调节块
- private TrackBar panddingTrackBar;
- // 设置容器内控件Margin属性的调节块
- private TrackBar marginTrackBar;
- /************ 文本框 ************/
- // 显示容器Padding属性值的调节块
- private TextBox pandingTrackBarValueTextBox;
- // 显示容器内控件Margin属性值的调节块
- private TextBox marginTrackBarValueTextBox;
- /************ 按钮 ************/
- // bottomPane内放置的按钮控件, 是一个Button类数组
- private Button[] buttons;
- ///
- /// 构造器, 初始化所有控件
- ///
- public MyForm() {
- /************ topPane控件初始化 ************/
- this.topPane = new FlowLayoutPanel();
- // 设置topPane容器停靠在窗体顶部
- this.topPane.Dock = DockStyle.Top;
- // 设置topPane容器布局方向: 从左到右
- this.topPane.FlowDirection = FlowDirection.LeftToRight;
- // 设置topPane容器的Padding属性
- this.topPane.Padding = new Padding(30);
- // 设置topPane容器的边框属性, 呈现3D效果
- this.topPane.BorderStyle = BorderStyle.Fixed3D;
- // 设置topPane容器不自动换行
- this.topPane.WrapContents = false;
- // 设置topPane容器具有自动滚动条
- this.topPane.AutoScroll = true;
- /************ flowDirectionComboBoxLabel控件初始化 ************/
- this.flowDirectionComboBoxLabel = new Label();
- // 设置flowDirectionComboBoxLabel控件Margin属性
- this.flowDirectionComboBoxLabel.Margin = new Padding(2, 6, 0, 3);
- // 设置flowDirectionComboBoxLabel控件呈现文本
- this.flowDirectionComboBoxLabel.Text = “布局方向:”;
- // 设置flowDirectionComboBoxLabel控件自动调整尺寸
- this.flowDirectionComboBoxLabel.AutoSize = true;
- // 将flowDirectionComboBoxLabel控件增加在topPane容器内
- this.topPane.Controls.Add(this.flowDirectionComboBoxLabel);
- /************ flowDirectionComboBox控件初始化 ************/
- this.flowDirectionComboBox = new ComboBox();
- // 设置flowDirectionComboBox控件Margin属性
- this.flowDirectionComboBox.Margin = new Padding(0, 3, 0, 3);
- // 设置flowDirectionComboBox控件下拉列表内容
- this.flowDirectionComboBox.Items.AddRange(new object[] {
- FlowDirection.LeftToRight,
- FlowDirection.RightToLeft,
- FlowDirection.TopDown,
- FlowDirection.BottomUp
- });
- // 设置flowDirectionComboBox控件下拉默认选中项
- this.flowDirectionComboBox.SelectedIndex = 0;
- // 设置flowDirectionComboBox控件选择项改变后通知事件
- this.flowDirectionComboBox.SelectedIndexChanged +=
- new EventHandler(FlowDirectionComboBoxSelectedValueChanged);
- // 将flowDirectionComboBox控件增加在topPane容器内
- this.topPane.Controls.Add(this.flowDirectionComboBox);
- /************ wrapCheckBox控件初始化 ************/
- this.wrapCheckBox = new CheckBox();
- // 设置wrapCheckBox控件Margin属性
- this.wrapCheckBox.Margin = new Padding(20, 5, 0, 5);
- // 设置wrapCheckBox控件自动调整尺寸
- this.wrapCheckBox.AutoSize = true;
- // 设置wrapCheckBox控件呈现文本
- this.wrapCheckBox.Text = “是否自动换行”;
- // 设置wrapCheckBox控件选中状态改变通知事件
- this.wrapCheckBox.CheckedChanged += new EventHandler(WarpCheckBoxCheckedChanged);
- // 将wrapCheckBox控件增加在topPane容器内
- this.topPane.Controls.Add(this.wrapCheckBox);
- /************ autoScrollCheckBox控件初始化 ************/
- this.autoScrollCheckBox = new CheckBox();
- // 设置autoScrollCheckBox控件Margin属性
- this.autoScrollCheckBox.Margin = new Padding(20, 5, 0, 5);
- // 设置autoScrollCheckBox控件自动调整尺寸
- this.autoScrollCheckBox.AutoSize = true;
- // 设置autoScrollCheckBox控件呈现文本
- this.autoScrollCheckBox.Text = “是否使用滚动条”;
- // 设置autoScrollCheckBox控件选中状态改变通知事件
- this.autoScrollCheckBox.CheckedChanged += new EventHandler(AutoScrollCheckBoxChanged);
- // 将autoScrollCheckBox控件增加在topPane容器内
- this.topPane.Controls.Add(this.autoScrollCheckBox);
- /************ panddingTrackBarLabel控件初始化 ************/
- this.panddingTrackBarLabel = new Label();
- // 设置panddingTrackBarLabel控件自动调整尺寸
- this.panddingTrackBarLabel.AutoSize = true;
- // 设置panddingTrackBarLabel控件Margin属性
- this.panddingTrackBarLabel.Margin = new Padding(20, 5, 0, 5);
- // 设置panddingTrackBarLabel控件呈现文本
- this.panddingTrackBarLabel.Text = “更改容器的 Padding:”;
- // 将panddingTrackBarLabel控件增加在topPane容器内
- this.topPane.Controls.Add(this.panddingTrackBarLabel);
- /************ panddingTrackBar控件初始化 ************/
- this.panddingTrackBar = new TrackBar();
- // 设置panddingTrackBar控件Margin属性
- this.panddingTrackBar.Margin = new Padding(0, 3, 3, 3);
- // 设置panddingTrackBar控件宽度属性
- this.panddingTrackBar.Width = 120;
- // 设置panddingTrackBar控件数值最小值
- this.panddingTrackBar.Minimum = 0;
- // 设置panddingTrackBar控件数值最大值
- this.panddingTrackBar.Maximum = 100;
- // 设置panddingTrackBar控件单位数值
- this.panddingTrackBar.TickFrequency = 1;
- // 设置panddingTrackBar控件数值改变时通知事件
- this.panddingTrackBar.ValueChanged += new EventHandler(PandingTrackBarValueChanged);
- // 将panddingTrackBar控件增加在topPane容器内
- this.topPane.Controls.Add(this.panddingTrackBar);
- /************ pandingTrackBarValueTextBox控件初始化 ************/
- this.pandingTrackBarValueTextBox = new TextBox();
- // 设置pandingTrackBarValueTextBox控件Margin属性
- this.pandingTrackBarValueTextBox.Margin = new Padding(0, 3, 3, 3);
- // 设置pandingTrackBarValueTextBox控件只读
- this.pandingTrackBarValueTextBox.ReadOnly = true;
- // 设置pandingTrackBarValueTextBox控件宽度属性
- this.pandingTrackBarValueTextBox.Width = 80;
- // 设置pandingTrackBarValueTextBox控件背景色属性
- this.pandingTrackBarValueTextBox.BackColor = SystemColors.Window;
- // 将pandingTrackBarValueTextBox控件增加在topPane容器内
- this.topPane.Controls.Add(this.pandingTrackBarValueTextBox);
- /************ marginTrackBarLabel控件初始化 ************/
- this.marginTrackBarLabel = new Label();
- // 设置marginTrackBarLabel控件自动调整尺寸
- this.marginTrackBarLabel.AutoSize = true;
- // 设置marginTrackBarLabel控件Margin属性
- this.marginTrackBarLabel.Margin = new Padding(20, 5, 0, 5);
- // 设置marginTrackBarLabel控件呈现文本
- this.marginTrackBarLabel.Text = “更改容器内控件的 Margin:”;
- // 将marginTrackBarLabel控件增加在topPane容器内
- this.topPane.Controls.Add(this.marginTrackBarLabel);
- /************ marginTrackBar控件初始化 ************/
- this.marginTrackBar = new TrackBar();
- // 设置marginTrackBar控件Margin属性
- this.marginTrackBar.Margin = new Padding(0, 3, 3, 3);
- // 设置marginTrackBar控件宽度属性
- this.marginTrackBar.Width = 120;
- // 设置marginTrackBar控件数值最小值
- this.marginTrackBar.Minimum = 0;
- // 设置marginTrackBar控件数值最大值
- this.marginTrackBar.Maximum = 100;
- // 设置marginTrackBar控件单位数值
- this.marginTrackBar.TickFrequency = 1;
- // 设置marginTrackBar控件数值改变时通知事件
- this.marginTrackBar.ValueChanged += new EventHandler(MarginTrackBarValueChanged);
- // 将marginTrackBar控件增加在topPane容器内
- this.topPane.Controls.Add(this.marginTrackBar);
- /************ marginTrackBarValueTextBox控件初始化 ************/
- this.marginTrackBarValueTextBox = new TextBox();
- // 设置marginTrackBarValueTextBox控件Margin属性
- this.marginTrackBarValueTextBox.Margin = new Padding(0, 3, 3, 3);
- // 设置marginTrackBarValueTextBox控件只读
- this.marginTrackBarValueTextBox.ReadOnly = true;
- // 设置marginTrackBarValueTextBox控件宽度属性
- this.marginTrackBarValueTextBox.Width = 80;
- // 设置marginTrackBarValueTextBox控件背景色属性
- this.marginTrackBarValueTextBox.BackColor = SystemColors.Window;
- // 将marginTrackBarValueTextBox控件增加在topPane容器内
- this.topPane.Controls.Add(this.marginTrackBarValueTextBox);
- // 将topPane容器增加到窗体上
- this.Controls.Add(this.topPane);
- /************ bottomPane容器初始化 ************/
- this.bottomPane = new FlowLayoutPanel();
- // 设置bottomPane容器停靠在窗体底部
- this.bottomPane.Dock = DockStyle.Bottom;
- // 设置bottomPane容器布局方向: 从左到右
- this.bottomPane.FlowDirection = FlowDirection.LeftToRight;
- // 设置bottomPane容器的Padding属性
- this.bottomPane.Padding = new Padding(30);
- // 设置bottomPane容器的边框属性, 呈现3D效果
- this.bottomPane.BorderStyle = BorderStyle.Fixed3D;
- /************ wrapCheckBox控件初始化 ************/
- // 初始化200个Button对象的数组
- this.buttons = new Button[200];
- // 初始化数组中的每一项
- for (int i = 0; i < this.buttons.Length; i++) {
- Button btn = new Button();
- // 设置按钮呈现文字
- btn.Text = i.ToString();
- // 设置按钮的尺寸
- btn.Size = new Size(100, 80);
- buttons[i] = btn;
- }
- // 将所有的按钮增加到bottomPane容器上
- this.bottomPane.Controls.AddRange(buttons);
- // 将bottomPane容器增加到窗体上
- this.Controls.Add(this.bottomPane);
- // 设置窗体最大化
- this.WindowState = FormWindowState.Maximized;
- // 设置窗体最小尺寸
- this.MinimumSize = new Size(800, 600);
- }
- ///
- /// 覆盖窗体OnLoad方法, 处理窗体第一次加载通知消息
- ///
- protected override void OnLoad(EventArgs e) {
- base.OnLoad(e);
- // 设置wrapCheckBox复选框Checked属性和bottomPane容器WrapContents属性值一致
- this.wrapCheckBox.Checked = this.bottomPane.WrapContents;
- // 设置autoScrollCheckBox复选框Checked属性和bottomPane容器AutoScroll属性值一致
- this.autoScrollCheckBox.Checked = this.bottomPane.AutoScroll;
- // 设置pandingTrackBarValueTextBox文本框文本为bottomPane容器Padding属性值
- this.pandingTrackBarValueTextBox.Text = this.bottomPane.Padding.All.ToString();
- // 设置marginTrackBarValueTextBox文本框文本为按钮控件Margin属性值
- this.marginTrackBarValueTextBox.Text = this.buttons[0].Margin.All.ToString();
- // 设置panddingTrackBar控件当前数值为bottomPane容器Padding属性值
- this.panddingTrackBar.Value = this.bottomPane.Padding.All;
- // 设置marginTrackBar控件当前数值为按钮控件Margin属性值
- this.marginTrackBar.Value = this.buttons[0].Margin.All;
- }
- ///
- /// 处理flowDirectionComboBox下拉列表控件选项改变事件
- ///
- private void FlowDirectionComboBoxSelectedValueChanged(object sender, EventArgs e) {
- // 设置bottomPane容器布局方向与flowDirectionComboBox下拉列表选项一致
- this.bottomPane.FlowDirection = (FlowDirection)this.flowDirectionComboBox.SelectedItem;
- }
- ///
- /// 处理wrapCheckBox复选框选择状态改变事件
- ///
- private void WarpCheckBoxCheckedChanged(object sender, EventArgs e) {
- // 设置bottomPane容器是否自动换行属性与wrapCheckBox复选框选中状态一致
- this.bottomPane.WrapContents = this.wrapCheckBox.Checked;
- }
- ///
- /// 处理autoScrollCheckBox复选框选择状态改变事件
- ///
- private void AutoScrollCheckBoxChanged(object sender, EventArgs e) {
- // 设置bottomPane容器是否具备滚动条属性与autoScrollCheckBox复选框选中状态一致
- this.bottomPane.AutoScroll = this.autoScrollCheckBox.Checked;
- }
- ///
- /// 处理panddingTrackBar控件数值改变事件
- ///
- private void PandingTrackBarValueChanged(object sender, EventArgs e) {
- // 设置bottomPane容器Padding属性与panddingTrackBar当前数值一致
- this.bottomPane.Padding = new Padding(this.panddingTrackBar.Value);
- // 设置pandingTrackBarValueTextBox文本框文本内容为bottomPane容器Padding属性值
- this.pandingTrackBarValueTextBox.Text = this.bottomPane.Padding.All.ToString();
- }
- ///
- /// 处理marginTrackBarValueTextBox控件数值改变事件
- ///
- private void MarginTrackBarValueChanged(object sender, EventArgs e) {
- // 设置所有按钮控件的Margin属性与marginTrackBar当前数值一致
- foreach (Button btn in this.buttons) {
- btn.Margin = new Padding(this.marginTrackBar.Value);
- }
- // 设置marginTrackBarValueTextBox文本框文本内容为按钮Margin属性值
- this.marginTrackBarValueTextBox.Text = this.buttons[0].Margin.All.ToString();
- }
- ///
- /// 覆盖父类OnResize方法, 处理窗体尺寸变化消息通知
- ///
- protected override void OnResize(EventArgs e) {
- base.OnResize(e);
- // 设置topPane容器高度为窗体客户区高度1/6
- this.topPane.Height = this.ClientSize.Height / 6;
- // 设置bottomPane容器高度为窗体客户区高度5/6
- this.bottomPane.Height = this.ClientSize.Height - this.ClientSize.Height / 6;
- }
- }
- ///
- /// 包含住方法的类
- ///
- static class Program {
- ///
- /// 应用程序的主入口点。
- ///
- static void Main() {
- Application.EnableVisualStyles();
- Application.SetCompatibleTextRenderingDefault(false);
- Application.Run(new MyForm());
- }
- }
- }
本节代码下载
本次代码中,我们用到了一些其它控件,包括:
- 文本标签控件(Label类);
- 文本框控件(TextBox类);
- 组合下拉列表框控件(ComboBox类);
- 数值调节滑块控件(TrackBar类)
代码中除了展示FlowLayoutPanel容器和上述控件的用法外(特别注意这些控件的事件处理),还展示了容器的Padding属性和控件(以Button为例)的Margin属性,仔细阅读代码,灵活的掌握上述内容。
还没有评论,来说两句吧...