Forma de C # winform y su adaptación de control

      Para mejorar la experiencia del usuario, el tamaño del formulario ya no se puede fijar (el usuario no puede cambiar el tamaño del formulario a voluntad), por lo que para adaptar el formulario a la resolución de la pantalla de la computadora, los controles en el formulario debe seguir la relación de cambio de la forma Variedad.

       A través de la búsqueda y el aprendizaje en línea, descubrí que varios tipos importantes tienen buenos métodos, así que agregué su código a mi propio proyecto y lo probé. Aunque puede realizar la función de cambio proporcional, todavía hay algunos controles fuera de lugar (el siguiente método 1 ), carga lenta de la página y otros problemas. En ausencia de un método mejor, resumamos estos dos métodos primero.

Uno, clase AutoSizeFormClass

    Consulte el enlace original del tipo grande: "Mejorar la adaptación de C # WinForm y sus controles" , "Los controles en la interfaz de C # Winform cambian con el tamaño de la ventana"

    1. El papel de la clase:

      (1) Úselo para registrar la posición inicial y el tamaño del formulario y sus controles;

      (2) De acuerdo con el tamaño cambiado de la forma, los cambios horizontales y verticales de sus controles se realizan proporcionalmente, lo cual es autoadaptación;

   2. Código de AutoSizeFormClass

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace FB100_RS485
{
    class AutoSizeFormClass
    {
        //(1).声明结构,只记录窗体和其控件的初始位置和大小。
        public struct controlRect
        {
            public int Left;
            public int Top;
            public int Width;
            public int Height;
        }
        //(2).声明 1个对象
        //注意这里不能使用控件列表记录 List nCtrl;,因为控件的关联性,记录的始终是当前的大小。
        //     public List oldCtrl= new List();//这里将西文的大于小于号都过滤掉了,只能改为中文的,使用中要改回西文
        //public List<controlRect> oldCtrl = new List<controlRect>();//20200305
        
        //存储控件名和他的位置
        public Dictionary<String, controlRect> oldCtrl = new Dictionary<String, controlRect>();//20200305

        int ctrlNo = 0;//1;
        //(3). 创建两个函数
        //(3.1)记录窗体和其控件的初始位置和大小,
        public void controllInitializeSize(Control mForm)
        {
            controlRect cR;
            cR.Left = mForm.Left; cR.Top = mForm.Top; cR.Width = mForm.Width; cR.Height = mForm.Height;
            //oldCtrl.Add(cR);//第一个为"窗体本身",只加入一次即可//20200305
            oldCtrl.Add(mForm.Name, cR);//20200305
            insertDictionary(mForm.Name, cR);//20200305

            AddControl(mForm);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用

            //this.WindowState = (System.Windows.Forms.FormWindowState)(2);//记录完控件的初始位置和大小后,再最大化
            //0 - Normalize , 1 - Minimize,2- Maximize
        }

        private void AddControl(Control ctl)
        {
            foreach (Control c in ctl.Controls)
            {  //**放在这里,是先记录控件的子控件,后记录控件本身
               //if (c.Controls.Count > 0)
               //   AddControl(c);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
                controlRect objCtrl;
                objCtrl.Left = c.Left; objCtrl.Top = c.Top; objCtrl.Width = c.Width; objCtrl.Height = c.Height;

                //oldCtrl.Add(c.Name, objCtrl);//20200305
                if (oldCtrl.ContainsKey(c.Name))//如果该键已经存在,则更改对应的值
                {
                    //MessageBox.Show("成功更改值");
                    oldCtrl[c.Name] = objCtrl;
                }
                else//该键不存在,则添加
                {
                    oldCtrl.Add(c.Name, objCtrl);//第一个为"窗体本身",只加入一次即可//20200305
                }

                insertDictionary(c.Name, objCtrl);

                //**放在这里,是先记录控件本身,后记录控件的子控件
                if (c.Controls.Count > 0)
                    AddControl(c);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用

            }
        }

        //(3.2)控件自适应大小,
        public void controlAutoSize(Control mForm)
        {

            if (ctrlNo == 0)
            { //*如果在窗体的Form1_Load中,记录控件原始的大小和位置,正常没有问题,但要加入皮肤就会出现问题,因为有些控件如dataGridView的的子控件还没有完成,个数少
              //*要在窗体的Form1_SizeChanged中,第一次改变大小时,记录控件原始的大小和位置,这里所有控件的子控件都已经形成
              
                controlRect cR;
                //  cR.Left = mForm.Left; cR.Top = mForm.Top; cR.Width = mForm.Width; cR.Height = mForm.Height;
                cR.Left = 0; cR.Top = 0; cR.Width = mForm.PreferredSize.Width; cR.Height = mForm.PreferredSize.Height;

                //oldCtrl.Add(mForm.Name, cR);//第一个为"窗体本身",只加入一次即可//20200305

                if (oldCtrl.ContainsKey(mForm.Name))//如果该键已经存在,则更改对应的值
                {
                    //MessageBox.Show("成功更改值");
                    oldCtrl[mForm.Name] = cR;
                }
                else//该键不存在,则添加
                {
                    oldCtrl.Add(mForm.Name, cR);//第一个为"窗体本身",只加入一次即可//20200305
                }

                AddControl(mForm);//窗体内其余控件可能嵌套其它控件(比如panel),故单独抽出以便递归调用
            }
            //float wScale = (float)mForm.Width / (float)oldCtrl[0].Width;//新旧窗体之间的比例,与最早的旧窗体
            //float hScale = (float)mForm.Height / (float)oldCtrl[0].Height;//.Height;
            float wScale = (float)mForm.Width / oldCtrl[mForm.Name].Width; ;//新旧窗体之间的比例,与最早的旧窗体
            float hScale = (float)mForm.Height / oldCtrl[mForm.Name].Height; ;//.Height;

            ctrlNo = 1;//进入=1,第0个为窗体本身,窗体内的控件,从序号1开始

            AutoScaleControl(mForm, wScale, hScale);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
        }

        private void AutoScaleControl(Control ctl, float wScale, float hScale)
        {
            int ctrLeft0, ctrTop0, ctrWidth0, ctrHeight0;
            //int ctrlNo = 1;//第1个是窗体自身的 Left,Top,Width,Height,所以窗体控件从ctrlNo=1开始
            foreach (Control c in ctl.Controls)
            { //**放在这里,是先缩放控件的子控件,后缩放控件本身
              //if (c.Controls.Count > 0)
              //   AutoScaleControl(c, wScale, hScale);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
              /*
                ctrLeft0 = oldCtrl[ctrlNo].Left;
                ctrTop0 = oldCtrl[ctrlNo].Top;
                ctrWidth0 = oldCtrl[ctrlNo].Width;
                ctrHeight0 = oldCtrl[ctrlNo].Height;
              */

                ctrLeft0 = oldCtrl[c.Name].Left;
                ctrTop0 = oldCtrl[c.Name].Top;
                ctrWidth0 = oldCtrl[c.Name].Width;
                ctrHeight0 = oldCtrl[c.Name].Height;

                //c.Left = (int)((ctrLeft0 - wLeft0) * wScale) + wLeft1;//新旧控件之间的线性比例
                //c.Top = (int)((ctrTop0 - wTop0) * h) + wTop1;
                c.Left = (int)((ctrLeft0) * wScale);//新旧控件之间的线性比例。控件位置只相对于窗体,所以不能加 + wLeft1
                c.Top = (int)((ctrTop0) * hScale);//
                c.Width = (int)(ctrWidth0 * wScale);//只与最初的大小相关,所以不能与现在的宽度相乘 (int)(c.Width * w);
                c.Height = (int)(ctrHeight0 * hScale);//

                AutoScaleFont(c);

                ctrlNo++;//累加序号
                         //**放在这里,是先缩放控件本身,后缩放控件的子控件
                if (c.Controls.Count > 0)
                    AutoScaleControl(c, wScale, hScale);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用


                if (ctl is DataGridView)
                {
                    DataGridView dgv = ctl as DataGridView;
                    Cursor.Current = Cursors.WaitCursor;

                    int widths = 0;
                    for (int i = 0; i < dgv.Columns.Count; i++)
                    {
                        dgv.AutoResizeColumn(i, DataGridViewAutoSizeColumnMode.AllCells);  // 自动调整列宽  
                        widths += dgv.Columns[i].Width;   // 计算调整列后单元列的宽度和                       
                    }
                    if (widths >= ctl.Size.Width)  // 如果调整列的宽度大于设定列宽  
                        dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;  // 调整列的模式 自动  
                    else
                        dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;  // 如果小于 则填充  

                    Cursor.Current = Cursors.Default;
                }
            }
        }


        private void AutoScaleFont(Control c)
        {
            string[] type = c.GetType().ToString().Split('.');
            string controlType = type[type.Length - 1];

            switch (controlType)
            {
                //case "Button":
                //    c.Font = new System.Drawing.Font("宋体", c.Height * 0.4f);
                //    break;

                //case "GroupBox":
                //    c.Font = new System.Drawing.Font("宋体", c.Height * 0.06f);
                //    break;
            }
        }


        private void insertDictionary(String name, controlRect cr)   //添加控件名和位置,如果名称重复则更新
        {
            Dictionary<String, controlRect> temp = new Dictionary<String, controlRect>();
            bool flag = false;
            foreach (var pair in oldCtrl)
            {
                if (pair.Key.ToString() == name)
                {
                    temp.Add(name, cr);
                    flag = true;
                }
            }
            if (flag == false)
            {
                oldCtrl.Add(name, cr);
            }
            foreach (var value in temp)
            {
                oldCtrl.Remove(value.Key.ToString());
                oldCtrl.Add(value.Key, value.Value);
            }
            temp.Clear();
        }
    }
}           

    3. Cómo utilizar

       1) Copie la clase adaptativa como un todo en el espacio de nombres de su proyecto y luego realice 3 pasos en el formulario que debe ser adaptable;
  2) Declare una instancia de la clase adaptativa;
  3) Agregue un evento de carga al formulario y en su método Form1_Load, llame al método de inicialización de la clase para registrar la posición inicial y el tamaño del formulario y sus controles;
  4) Agregue un evento SizeChanged al formulario, y en su método Form1_SizeChanged, llame al método adaptativo de la clase para completar la adaptación;

       Agregue el código de la siguiente manera en el código del formulario:

namespace FB100_RS485
{

    public partial class mainForm : Form
    {
        //1.声明自适应类实例
        AutoSizeFormClass asc = new AutoSizeFormClass();

        public mainForm()
        {
            InitializeComponent();

            //消除数据更新时的闪烁
            dataGridView2.DoubleBufferedDataGirdView(true);

            //如果加入"皮肤",则不能在Form1_Load中记录控件的大小和位置,因为有些控件如dataGridView的子控件还未完成
            //而要在在Form1_SizeChanged中,第一次改变时,记录控件的大小和位置
            skinEngine1.SkinFile = System.Environment.CurrentDirectory + @"\DiamondBlue.ssk";  //选择皮肤文件

        }

        /// <summary>
        /// 窗体加载,初始化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mainForm_Load(object sender, EventArgs e)
        {
            //2. 为窗体添加Load事件,并在其方法Form1_Load中,调用类的初始化方法,记录窗体和其控件的初始位置和大小
            //asc.controllInitializeSize(this);

            //RS485通讯配置默认参数
            rs232_init();
            //公共控件初始化
            comm_control_init();
        }


        private void mainForm_SizeChanged(object sender, EventArgs e)
        {
            //3.为窗体添加SizeChanged事件,并在其方法Form1_SizeChanged中,调用类的自适应方法,完成自适应
            asc.controlAutoSize(this);
        }
    }
}

     4. Resumen

      (1) La página se carga lentamente, lo que puede provocar la dislocación de los controles en algunos casos;

      (2) Cuando la interfaz se agranda, el texto de los controles no seguirá el cambio, el espacio entre los controles será muy grande y la vista general no estará muy coordinada;

Dos, método dos

      1. Consulte el enlace original: "El tamaño del control de C # Winform escala proporcionalmente al tamaño del formulario"

      2. Código

        public mainForm()
        {
            InitializeComponent();
            x = this.Width;
            y = this.Height;
            setTag(this);
        }

        #region 控件大小随窗体大小等比例缩放
        private float x;//定义当前窗体的宽度
        private 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)
                {
                    string[] mytag = con.Tag.ToString().Split(new char[] { ';' });
                    //根据窗体缩放的比例确定控件的值
                    con.Width = Convert.ToInt32(System.Convert.ToSingle(mytag[0]) * newx);//宽度
                    con.Height = Convert.ToInt32(System.Convert.ToSingle(mytag[1]) * newy);//高度
                    con.Left = Convert.ToInt32(System.Convert.ToSingle(mytag[2]) * newx);//左边距
                    con.Top = Convert.ToInt32(System.Convert.ToSingle(mytag[3]) * newy);//顶边距
                    Single currentSize = System.Convert.ToSingle(mytag[4]) * newy;//字体大小
                    con.Font = new Font(con.Font.Name, currentSize, con.Font.Style, con.Font.Unit);
                    if (con.Controls.Count > 0)
                    {
                        setControls(newx, newy, con);
                    }
                }
            }
        }

        private void mainForm_Resize(object sender, EventArgs e)
        {
            //一定要在属性设置中,设置窗体的MinimumSize属性,设置可变的最小尺寸
            //当窗体缩小到一定程度时,窗体中的控件会产生一定程度的错位!

            float newx = (this.Width) / x;
            float newy = (this.Height) / y;
            setControls(newx, newy, this);
        }

        #endregion

    3. Atención

       (1) La inicialización en ancho y alto se proporciona para no olvidar;
       (2) un método en el que Form1_Resize el formulario necesita su propio proceso de configuración manual de cambio de tamaño de "Propiedades" (FIG se encuentra en el cambio de tamaño, doble espacio en blanco puede más adelante);
       (3) no necesita escalado de fuentes, puede comentar las siguientes dos líneas de código.

Single currentSize = System.Convert.ToSingle(mytag[4]) * newy;//字体大小
con.Font = new Font(con.Font.Name, currentSize, con.Font.Style, con.Font.Unit);

para resumir:

     El formulario no se puede reducir infinitamente, porque cuando el formulario se reduce en cierta medida, los controles en el formulario estarán desalineados, por lo que se debe establecer el tamaño mínimo del formulario (estableciendo la propiedad Tamaño Mínimo del formulario).

Supongo que te gusta

Origin blog.csdn.net/zwb_578209160/article/details/104715653
Recomendado
Clasificación