none
winfrom窗体控件自适应的原理是怎样的,具体该怎么实现?我自己的实现为何没有效果? RRS feed

  • 问题

  • 如题,请MSDN上各路神仙,大神来解答小弟我的困惑吧!!

     public void GetAllControlScaleRange(Control c)
            {
                if (c.Controls.Count > 0)
                {
                    ////表示是容器控件
                    if (c != this)
                    {
                        //表示除根元素以外的元素才计算缩放比率
                        //计算坐标比率,以及大小比率
                        //if (c.Parent.GetType().Name == "TableLayoutPanel")
                        //{}
                        //if (c.Parent.GetType().Name == "Panel")
                        //{}
                        decimal tempWidthRange = c.Parent.Width == 0 ? 0 : (decimal)c.Width / c.Parent.Width;
                        decimal tempHeightRange = c.Parent.Height == 0 ? 0 : (decimal)c.Height / c.Parent.Height;
                        if (tempWidthRange < 3 || tempHeightRange<3)
                        {}

                        //decimal tempX = c.Parent.Location.X == 0 ? 0 : (decimal)c.Location.X / c.Parent.Location.X;
                        //decimal tempY = c.Parent.Location.Y == 0 ? 0 : (decimal)c.Location.Y / c.Parent.Location.Y;
                        //AllControlRange acrObj = new AllControlRange() { ctl = c, ctlWidthRange = tempWidthRange, ctlHeightRange = tempHeightRange, ctlX = tempX, ctlY = tempY };
                        AllControlRange acrObj = new AllControlRange() { ctl = c, ctlWidthRange = tempWidthRange, ctlHeightRange = tempHeightRange };
                        globalCtlRangeList.Add(acrObj);

                    }
                    //添加子元素
                    foreach (Control item in c.Controls)
                    {
                        GetAllControlScaleRange(item);
                    }
                }
                else
                {
                    if (c != this)
                    {
                        //表示除根元素以外的元素才计算缩放比率
                        //计算坐标比率,以及大小比率
                        decimal tempWidthRange = c.Parent.Width == 0 ? 0 : (decimal)c.Width / c.Parent.Width;
                        decimal tempHeightRange = c.Parent.Height == 0 ? 0 : (decimal)c.Height / c.Parent.Height;


                        //decimal tempX = c.Parent.Location.X == 0 ? 0 : (decimal)c.Location.X / c.Parent.Location.X;
                        //decimal tempY = c.Parent.Location.Y == 0 ? 0 : (decimal)c.Location.Y / c.Parent.Location.Y;
                        //AllControlRange acrObj = new AllControlRange() { ctl = c, ctlWidthRange = tempWidthRange, ctlHeightRange = tempHeightRange, ctlX = tempX, ctlY = tempY };
                        AllControlRange acrObj = new AllControlRange() { ctl = c, ctlWidthRange = tempWidthRange, ctlHeightRange = tempHeightRange };
                        globalCtlRangeList.Add(acrObj);
                    }
                }
            }

                                               

     public void CalcAllControlLOrP(Control c)
            {
                if (c.Controls.Count > 0)
                {
                    ////表示是容器控件
                    if (c != this)
                    {
                        //表示除根元素以外的元素才计算缩放比率
                        //计算坐标比率,以及大小比率
                        AllControlRange tempAcr = globalCtlRangeList.Find(n => n.ctl == c);
                        if (tempAcr != null)
                        {
                            if (c.Width <40 || c.Height == 0)
                            { }
                            int width = (int)(tempAcr.ctlWidthRange * c.Width);
                            int height = (int)(tempAcr.ctlHeightRange * c.Height);
                            int x=0, y = 0;
                            //x = (int)(c.Location.X * tempAcr.ctlWidthRange);
                            //y = (int)(c.Location.Y * tempAcr.ctlHeightRange);

                            if (width > c.Width)
                            {
                                //表示宽度放大
                                x = c.Left+ (width - c.Width);
                            }
                            else
                            {
                                //表示宽度缩小
                                x =c.Left - (c.Width - width);
                            }

                            if (height > c.Height)
                            {
                                //表示高度放大
                                y = c.Top + (height - c.Height);
                            }
                            else
                            {
                                //表示高度缩小
                                y = c.Top - (c.Height - height);
                            }
                            //x = x < 0 ? 0 : x;
                            //y = y < 0 ? 0 : y;
                            //c.Location = new Point(x, y);
                            c.Left = x;
                            c.Top = y;
                            c.Width = width;
                            c.Height = height;
                        }
                    }
                    //添加子元素
                    foreach (Control item in c.Controls)
                    {
                        CalcAllControlLOrP(item);
                    }
                }
                else
                {
                    if (c != this)
                    {
                        //表示除根元素以外的元素才计算缩放比率
                        //计算坐标比率,以及大小比率
                        AllControlRange tempAcr = globalCtlRangeList.Find(n => n.ctl == c);
                        if (tempAcr != null)
                        {
                            int width = (int)(tempAcr.ctlWidthRange * c.Width);
                            int height = (int)(tempAcr.ctlHeightRange * c.Height);
                            if (width == 0 || height == 0)
                            { }
                            int x=0, y = 0;
                            //x = (int)(c.Location.X * tempAcr.ctlWidthRange);
                            //y = (int)(c.Location.Y * tempAcr.ctlHeightRange);
                            if (c.Text == "测试的按钮1")
                            { }
                            if (width > c.Width)
                            {
                                //表示宽度放大
                                x = c.Left + (width - c.Width);
                            }
                            else
                            {
                                //表示宽度缩小
                                x = c.Left - (c.Width - width);
                            }

                            if (height > c.Height)
                            {
                                //表示高度放大
                                y = c.Top + (height - c.Height);
                            }
                            else
                            {
                                //表示高度缩小
                                y = c.Top - (c.Height - height);
                            }

                            //x = x < 0 ? 0 : x;
                            //y = y < 0 ? 0 : y;
                            //c.Location = new Point(x, y);
                            c.Left = x;
                            c.Top = y;
                            c.Width = width;
                            c.Height = height;
                        }
                    }
                }

            }

      private void FrmAutoScale_Load(object sender, EventArgs e)
            {
                Control s = this;
                GetAllControlScaleRange(s);

                //asc.controllInitializeSize(this);

            }

       private void FrmAutoScale_SizeChanged(object sender, EventArgs e)
            {
                //特别注意:
                //用法详解:
                //1.标注为①的代码可以根据实际情况放在窗体或容器控件的构造函数里面,也可以直接与CalcAllControlLOrP在一起使用,具体根据实际情况来定,
                //2.主要原理是,首先自适应窗体要调用GetAllControlScaleRange函数计算所有子控件的位置和大小比率,然后,待自适应窗体设置新的大小后,
                //调用CalcAllControlLOrP函数,根据之前计算的比率,重新计算所有控件的新的位置和大小。

                //①。首先传入容器控件或窗体来计算所有子控件的位置和大小比率
                Control s = this;//传入的控件可以是容器控件或者窗体
                //GetAllControlScaleRange(s);

                //②。设置容器控件或窗体新的大小后,在此根据之前的比率来计算新的所有控件的位置和大小
                //s.Width = 800; s.Height = 600;


                if (globalCtlRangeList.Count != 0) { CalcAllControlLOrP(s); }

                //asc.controlAutoSize(this);

            }

    2018年5月8日 11:43

全部回复

  • 不需要这么复杂的计算,设置停靠Anchor=DockLeft,DockRight,对占满剩余的空间的控件设置Dock.Fill

    最将它们丢入到DockContainer,StripContainer控件中。


    专注于.NET ERP/CRM开发框架,C/S架构,SQL Server + ORM(LLBL Gen Pro) + Infragistics WinForms

    2018年5月9日 0:36
  • 你好,

    你可以参考一下下面的博客,使用一个类来做的

    using System.Collections.Generic;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp
    {
        class AutoSizeFormClass
        {
            //(1).声明结构,只记录窗体和其控件的初始位置和大小。  
            public struct controlRect
            {
                public int Left;
                public int Top;
                public int Width;
                public int Height;
            }
            //(2).声明 1个对象  
            //注意这里不能使用控件列表记录 List<Control> nCtrl;,因为控件的关联性,记录的始终是当前的大小。  
            public List<controlRect> oldCtrl;
            //int ctrl_first = 0;  
            //(3). 创建两个函数  
            //(3.1)记录窗体和其控件的初始位置和大小,  
            public void controllInitializeSize(Form mForm)
            {
                // if (ctrl_first == 0)  
                {
                    //  ctrl_first = 1;  
                    oldCtrl = new List<controlRect>();
                    controlRect cR;
                    cR.Left = mForm.Left; cR.Top = mForm.Top; cR.Width = mForm.Width; cR.Height = mForm.Height;
                    oldCtrl.Add(cR);
                    foreach (Control c in mForm.Controls)
                    {
                        controlRect objCtrl;
                        objCtrl.Left = c.Left; objCtrl.Top = c.Top; objCtrl.Width = c.Width; objCtrl.Height = c.Height;
                        oldCtrl.Add(objCtrl);
                    }
                }
                // this.WindowState = (System.Windows.Forms.FormWindowState)(2);//记录完控件的初始位置和大小后,再最大化  
                //0 - Normalize , 1 - Minimize,2- Maximize  
            }
            //(3.2)控件自适应大小,  
            public void controlAutoSize(Form mForm)
            {
                //int wLeft0 = oldCtrl[0].Left; ;//窗体最初的位置  
                //int wTop0 = oldCtrl[0].Top;  
                ////int wLeft1 = this.Left;//窗体当前的位置  
                //int wTop1 = this.Top;  
                float wScale = (float)mForm.Width / (float)oldCtrl[0].Width;//新旧窗体之间的比例,与最早的旧窗体  
                float hScale = (float)mForm.Height / (float)oldCtrl[0].Height;//.Height;  
                int ctrLeft0, ctrTop0, ctrWidth0, ctrHeight0;
                int ctrlNo = 1;//第1个是窗体自身的 Left,Top,Width,Height,所以窗体控件从ctrlNo=1开始  
                foreach (Control c in mForm.Controls)
                {
                    ctrLeft0 = oldCtrl[ctrlNo].Left;
                    ctrTop0 = oldCtrl[ctrlNo].Top;
                    ctrWidth0 = oldCtrl[ctrlNo].Width;
                    ctrHeight0 = oldCtrl[ctrlNo].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);//  
                    ctrlNo += 1;
                }
            }
        }
    }
    

    #Winforms

    using System;
    using System.Data.SqlClient;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp
    {
        public partial class Form3 : Form
        {
            //1.声明自适应类实例  
            AutoSizeFormClass asc = new AutoSizeFormClass();
            public Form3()
            {
                InitializeComponent();
            }
    
            private void Form3_Load(object sender, EventArgs e)
            {
                //string connString = @"Data Source=(localdb)\MSSQLLocalDB; AttachDbFilename=D:\Data\LocalDb\RepositoryDB.mdf; Integrated Security=True;";
                //using (var conn = new SqlConnection(connString))
                //{
                //    string sqlString = @"select TOTALMEN from TOTALMEMBERSHIP where ID =1";
                //    using (var command = new SqlCommand(sqlString,conn))
                //    {
                //        conn.Open();
                //        var result = command.ExecuteScalar();
                //        textBox1.Text = result.ToString();
                //    }
                //}
                asc.controllInitializeSize(this);
            }
    
            private void Form3_SizeChanged(object sender, EventArgs e)
            {
                asc.controlAutoSize(this);
            }
        }
    }
    

    https://www.cnblogs.com/weiterli/p/7833279.html

    Best regards,

    Zhanglong


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2018年5月9日 5:36
    版主
  • 此方式我试过了,有问题,当你界面上多放几个控件就不行了,有问题,或者你嵌套几个容器控件,里面在放子控件,就有问题了。
    2018年5月10日 8:07
  • 你好,

    你可以按照Shuanghua Li的建议使用Dock 和 Anchor 属性来做。下面的链接有一个例子,你可以参考一下。

    https://www.techrepublic.com/article/manage-winform-controls-using-the-anchor-and-dock-properties/

    Best regards,

    Zhanglong


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2018年5月16日 8:48
    版主
  • 恩,谢谢您的回答,您说的方式确实大部分情况基本都可以用Dock和Anchor属性来解决。。。

    但是,其实我就是想知道用代码的方式如何来自动处理这种自适应问题。就是想自己写一段通用的代码来解决winform自适应问题。。只是我想在苦于还没搞清楚winform自适应的的原理,所以写的代码难免也有问题。

    比如:我的想法是,首先根据窗体首次加载时的大小,来计算里面所有控件包含基本控件和容器控件的大小比率,然后当窗体最大化或者最小化,或者由用户拖动改变大小,也就是当它的Size发生改变时,就以当前改变后的大小按照之前的大小比率重新计算,即得到当前改变大小后的所有控件的大小。

    但是这里有个问题,就是自适应时,应该是大小和位置,同时按照比率来缩放,那么我的问题来了,就是位置如何来计算。这个我还没搞明白。求给位清楚的大神,给点意见和提示!!还请MSDN上路过的各路神仙,给个指点,点化一下我!!

    2018年5月19日 3:06