Winform中实现窗体控件适配(自适应窗体)布局_通过C#代码方式

1.1、未启用控件缩放的实现效果

即:未启用控件缩放效果代码时,控件内容都是固定在窗体界面的指定位置,不会跟随窗体的拉伸,放大而进行适配,如下图所示

1.2、启用控件缩放的实现效果

即:启用控件缩放效果代码时,控件内容会跟随窗体的拉伸,放大而进行适配,如下图所示

2.1、控件随窗体缩放适配思路

实现思路是:

①在窗体初始化时先获取窗体的宽度和高度,然后;

②遍历窗体控件进行初始化设置缩放位置;

③在窗体变化时获取当前窗体的宽度和高度,然后遍历窗体控件进行设置。

2.2、控件随窗体适配的核心代码

#region 控件大小随窗体大小等比例缩放

        private readonly float x; //定义当前窗体的宽度
        private readonly float y; //定义当前窗体的高度

        private void setTag(Control cons)
        {
            foreach (Control con in cons.Controls)
            {
                con.Tag = con.Width + ";" + con.Height + ";" + con.Left + ";" + con.Top + ";" + con.Font.Size;
                if (con.Controls.Count > 0) setTag(con);
            }
        }

        private void setControls(float newx, float newy, Control cons)
        {
            //遍历窗体中的控件,重新设置控件的值
            foreach (Control con in cons.Controls)
                //获取控件的Tag属性值,并分割后存储字符串数组
                if (con.Tag != null)
                {
                    var mytag = con.Tag.ToString().Split(';');
                    //根据窗体缩放的比例确定控件的值
                    con.Width = Convert.ToInt32(Convert.ToSingle(mytag[0]) * newx); //宽度
                    con.Height = Convert.ToInt32(Convert.ToSingle(mytag[1]) * newy); //高度
                    con.Left = Convert.ToInt32(Convert.ToSingle(mytag[2]) * newx); //左边距
                    con.Top = Convert.ToInt32(Convert.ToSingle(mytag[3]) * newy); //顶边距
                    var currentSize = Convert.ToSingle(mytag[4]) * newy; //字体大小                   
                    if (currentSize > 0) con.Font = new Font(con.Font.Name, currentSize, con.Font.Style, con.Font.Unit);
                    con.Focus();
                    if (con.Controls.Count > 0) setControls(newx, newy, con);
                }
        }


        /// <summary>
        /// 重置窗体布局
        /// </summary>
        private void ReWinformLayout()
        {
            var newx = Width / x;
            var newy = Height / y;
            setControls(newx, newy, this);

        }

        #endregion

三、使用方法

3.1、在窗体构造函数内初始化适配

        //注意:UIComponetForm是自己需进行适配的窗体名称
        public UIComponetForm()
        {
            InitializeComponent();

            #region   初始化控件缩放

            x = Width;
            y = Height;
            setTag(this);

            #endregion 
        }

3.2、重置缩放布局

②选中事件,双击Resize即可生成重置窗口布局的基础代码

        private void Form1_Resize(object sender, EventArgs e)
        {
            //重置窗口布局
            ReWinformLayout();
        }

封装

是的,你可以将自适应布局的代码封装成一个单独的类或方法,以便在多个窗体中重复使用。以下是一个示例,演示如何将上述代码封装为一个可重用的类:

using System;
using System.Drawing;
using System.Windows.Forms;

public class FormLayoutHelper
{
    private float xRatio;
    private float yRatio;

    public FormLayoutHelper(Form form)
    {
        // 初始化窗体宽度和高度比例
        xRatio = form.Width;
        yRatio = form.Height;
        SetTag(form);
    }

    private void SetTag(Control cons)
    {
        foreach (Control con in cons.Controls)
        {
            con.Tag = $"{con.Width};{con.Height};{con.Left};{con.Top};{con.Font.Size}";
            if (con.Controls.Count > 0)
                SetTag(con);
        }
    }

    public void ResizeControls(Form form)
    {
        float newx = form.Width / xRatio;
        float newy = form.Height / yRatio;
        SetControls(newx, newy, form);
    }

    private void SetControls(float newx, float newy, Control cons)
    {
        foreach (Control con in cons.Controls)
        {
            if (con.Tag != null)
            {
                var mytag = con.Tag.ToString().Split(';');
                con.Width = Convert.ToInt32(Convert.ToSingle(mytag[0]) * newx);
                con.Height = Convert.ToInt32(Convert.ToSingle(mytag[1]) * newy);
                con.Left = Convert.ToInt32(Convert.ToSingle(mytag[2]) * newx);
                con.Top = Convert.ToInt32(Convert.ToSingle(mytag[3]) * newy);
                var currentSize = Convert.ToSingle(mytag[4]) * newy;
                if (currentSize > 0)
                    con.Font = new Font(con.Font.Name, currentSize, con.Font.Style, con.Font.Unit);
                con.Focus();
                if (con.Controls.Count > 0)
                    SetControls(newx, newy, con);
            }
        }
    }
}

使用示例:

在你的 Form1 类中,可以像这样使用 FormLayoutHelper

public partial class Form1 : Form
{
    private FormLayoutHelper layoutHelper;

    public Form1()
    {
        InitializeComponent();
        layoutHelper = new FormLayoutHelper(this);
    }

    private void Form1_Resize(object sender, EventArgs e)
    {
        layoutHelper.ResizeControls(this);
    }
}

这样,你就可以在多个窗体中使用 FormLayoutHelper 类来实现自适应布局,而不必在每个窗体中重复编写相同的代码。

封装2

using System;
using System.Drawing;
using System.Windows.Forms;
public static class FormLayoutHelper
{
 /// <summary>
 /// 使窗体及其子控件自适应分辨率
 /// </summary>
 /// <param name="form">要自适应的窗体</param>
 public static void EnableAdaptiveLayout(this Form form)
 {
 // 记录初始尺寸
 form.Tag = $"{form.Width};{form.Height}";
 // 保存初始布局信息
 SaveControlLayout(form);
 // 绑定Resize事件
 form.Resize += (sender, e) =>
 {
 if (form.WindowState == FormWindowState.Minimized) return;
 ResizeControls(form);
 };
 }
 /// <summary>
 /// 保存控件的布局信息到Tag属性
 /// </summary>
 private static void SaveControlLayout(Control control)
 {
 foreach (Control con in control.Controls)
 {
 con.Tag = $"{con.Width};{con.Height};{con.Left};{con.Top};{con.Font.Size}";
 if (con.Controls.Count > 0)
 SaveControlLayout(con);
 }
 }
 /// <summary>
 /// 根据新的窗体尺寸调整控件大小和位置
 /// </summary>
 private static void ResizeControls(Control control)
 {
 // 获取初始尺寸
 var originalSize = control.Tag.ToString().Split(';');
 var originalWidth = Convert.ToSingle(originalSize[0]);
 var originalHeight = Convert.ToSingle(originalSize[1]);
 // 计算缩放比例
 var newX = control.Width / originalWidth;
 var newY = control.Height / originalHeight;
 // 调整子控件
 AdjustControls(newX, newY, control);
 }
 /// <summary>
 /// 调整控件大小和位置
 /// </summary>
 private static void AdjustControls(float newX, float newY, Control cons)
 {
 foreach (Control con in cons.Controls)
 {
 if (con.Tag != null)
 {
 var mytag = con.Tag.ToString().Split(';');
 con.Width = Convert.ToInt32(Convert.ToSingle(mytag[0]) * newX);
 con.Height = Convert.ToInt32(Convert.ToSingle(mytag[1]) * newY);
 con.Left = Convert.ToInt32(Convert.ToSingle(mytag[2]) * newX);
 con.Top = Convert.ToInt32(Convert.ToSingle(mytag[3]) * newY);
 var currentSize = Convert.ToSingle(mytag[4]) * newY;
 if (currentSize > 0)
 con.Font = new Font(con.Font.Name, currentSize, con.Font.Style, con.Font.Unit);
 if (con.Controls.Count > 0)
 AdjustControls(newX, newY, con);
 }
 }
 }
}

使用方法:

  1. 在你的项目中添加这个 FormLayoutHelper 类.

  2. 在需要自适应的窗体的构造函数中调用 EnableAdaptiveLayout() 方法:

    public partial class MyForm : Form
    {
    public MyForm()
    {
    InitializeComponent();
    this.EnableAdaptiveLayout(); 
    }
    }
    

    优点:

  • 代码封装: 将自适应逻辑封装到一个单独的类中,提高了代码的可读性和可维护性。

  • 易于使用: 只需要调用一个方法即可启用自适应布局。

  • 递归处理: 可以处理嵌套的子控件。 注意:

  • 该方法通过调整控件的大小和位置来实现自适应,可能不适用于所有布局场景。

  • 对于复杂的布局,建议使用 TableLayoutPanel 或 FlowLayoutPanel 等控件来实现更好的自适应效果。

    控件多 了容易卡顿

    可以考虑使用定时器(Timer)或者异步操作来延迟执行布局调整,而不是每次 Resize 事件都立即调整布局 具体怎么实现, 加一种使用防抖来实现最后放下的鼠标时候才调整