WinForm窗体自适应分辨率

摘要:
///控件的左属性///&lt///控件的右属性///&lt///控件权重属性///&lt///控制项的高属性////&lt///控件的字体大小属性///lt;}然后声明一个泛型类型以保存由所有控件的位置和大小信息生成的结构信息。

我们自己编写程序的界面,会遇到各种屏幕分辨率,只有自适应才能显的美观。实际上,做到这点也很简单,就是首先记录窗体和它上面控件的初始位置和大小,当窗体改变比例时,其控件的位置和大小也按此比例变化即可。因为窗体上控件的位置和大小是相对于自己所在的窗体的,也就是所谓的窗口坐标。  

  在这里我们只考虑相对于自己窗体的窗口坐标更简单,也就是成比例变化。为了多个窗体共用,我在这里创建一个类AutoSizeFormClass ,1.使用它去记录窗体和其控件的初始位置和大小,2.判断窗体中的控件是否为容器控件,如果是记录容器控件中的控件的初始位置和大小3.根据窗体变化了的大小,成比例地实现其控件的水平和垂直方向的变化,也就是自适应。
 
二。使用方法
  使用方法很简单,
  1.把自适应的类整体复制到你的工程命名空间里,
     然后在需要自适应的窗体中做2步即可:
  2.声明自适应类实例。
  3.为窗体添加大小改变事件,并在其方法中,调用类的自适应方法,完成自适应
 
    通过上面的介绍我们会发现其中的几个实现难点:
    1.如何保存窗体的以及其中控件的位置以及大小等属性,当然我们最常用的方法就是自己定义一个实体,实体中包含我们需要保持的属性(主要包括left,top,width,height,以及fontsize属性)这个我提供的解决方案是定义一个数据结构。
    普及一下结构体的知识:结构体中包含其中要存储的数据,使用结构体的好处在于可以将不同类型的数据有序的组合在一起,结构造出一个新的数据类型,不占内存空间,只用定义结构体的变量时才开辟内存空间,结构体类型的变量在内存依照其成员顺序顺序排列,所占内存空间的大小是其全体成员所占空间的总和,结构体可以作为函数的参数,函数也可以返回结构体。
看我们定义的结构体:
 
 /// <summary>
        /// 声明一个结构,用于保存控件位置的基本属性。
        /// </summary>
        public struct controlRect
        {
            /// <summary>
            /// 控件的left属性
            /// </summary>
            public int Left;
            /// <summary>
            /// 控件的Right属性
            /// </summary>
            public int Top;
            /// <summary>
            /// 控件的Weight属性
            /// </summary>
            public int Width;
            /// <summary>
            /// 控件的High属性
            /// </summary>
            public int Height;
            /// <summary>
            /// 控件的Fontsize属性
            /// </summary>
            public float FontSize;
        }
    然后声明一个泛型用来保存所有控件位置以及大小信息产生的结构体信息。
 
    //这里只是列出两个容器控件分别为panel控件和groupbox控件
                if (c.GetType().ToString() == "System.Windows.Forms.Panel")
                {
                    //要执行的代码
                }
                //如果是GroupBox控件
                if (c.GetType().ToString() == "System.Windows.Forms.GroupBox")
                {
                    //要执行的代码
                }
 

    但我发现自己很难把所有的控件都想全了,即使是想全了也会重复太多的代码,最后采取了一个很有效的方法就是加上这个判断:

            if (c.Controls.Count > 0)

    一旦这个判断成立就说明这个控件就是一个容器控件了。

问题3.递归调用保存控件信息类,实现所有控件(包括容器控件)的位置和大小信息的保存。

   问题4.如何保存画窗体时窗体的大小,听起来有些别嘴,其实也可以说是你想要窗体呈现的大小,这个大大家好像会有疑问但虽然说窗体是控件的一种,但是进过我的实现,当我们改变分辨率的同时,比如我们原来设置窗体每次打开时最大化显示,但是无论我们编写程序时设置的窗体的大小多大,我们运行起来时窗体都会占满整个屏幕,这也是出现由于分辨率改变,大窗体中部分控件无法显示完全的原因。比如我们的做的这个很大的登陆界面,看看效果:

        小分辨率下的情况:

WinForm窗体自适应分辨率第1张

       大分辨率下应该是这样:

WinForm窗体自适应分辨率第2张

        ​我们会发现窗体最大化了。但是窗体中的控件没有跟上。
        说了这么多我想大家都迫不及待的想看代码了:
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace AutoSizeFormClass
{
    public class AutoSizeFormClass
    {
        /// <summary>
        /// 声明一个结构,用于保存控件位置的基本属性。
        /// </summary>
        public struct controlRect
        {
            /// <summary>
            /// 控件的left属性
            /// </summary>
            public int Left;
            /// <summary>
            /// 控件的Right属性
            /// </summary>
            public int Top;
            /// <summary>
            /// 控件的Weight属性
            /// </summary>
            public int Width;
            /// <summary>
            /// 控件的High属性
            /// </summary>
            public int Height;
            /// <summary>
            /// 控件的Fontsize属性
            /// </summary>
            public float FontSize;
        }
        /// <summary>
        /// 声明一个泛型,类型为什么的保存控件属性的结构类,
        /// </summary>
        public List<controlRect> oldCtrl = new List<controlRect>();
        int ctrlNo = 0;//初始化标识控件的变量为0,表示窗体本身。   
        /// <summary>
        /// 保存控件的位置和大小信息
        /// </summary>
        /// <param name="ctl">需要被保存的控件</param>
        private void AddControl(Control ctl)
        {
            foreach (Control c in ctl.Controls)
            {  
                controlRect objCtrl;
                objCtrl.Left = c.Left;
                objCtrl.Top = c.Top;
                objCtrl.Width = c.Width;
                objCtrl.Height = c.Height;
                objCtrl.FontSize = c.Font.Size;
                oldCtrl.Add(objCtrl);
                //**放在这里,是先记录控件本身,后记录控件的子控件,重点是前后要一致
                if (c.Controls.Count > 0)
                    AddControl(c);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
            }
        }
        /// <summary>
        /// 窗体自适应分辨率类
        /// </summary>
        /// <param name="mForm">需要进行设置的窗体</param>
        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.Width = int.Parse(mForm.Tag.ToString().Split(',')[0]);
                cR.Height = int.Parse(mForm.Tag.ToString().Split(',')[1]);
                cR.FontSize = mForm.Font.Size;
                oldCtrl.Add(cR);//第一个为"窗体本身",只加入一次即可                
                AddControl(mForm);//窗体内其余控件可能嵌套其它控件(比如panel),故单独抽出以便递归调用
            }
            float wScale = (float)mForm.Width / (float)oldCtrl[0].Width;//新旧窗体之间的比例,与最早的旧窗体比较
            float hScale = (float)mForm.Height / (float)oldCtrl[0].Height;//.Height;
            ctrlNo = 1;//进入=1,第0个为窗体本身,窗体内的控件,从序号1开始
            AutoScaleControl(mForm, wScale, hScale);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
        }
        /// 设置控件的属性
        /// </summary>
        /// <param name="ctl">需要设置的控件</param>
        /// <param name="wScale">调整的高度比例</param>
        /// <param name="hScale">调整的宽度比例</param>
        private void AutoScaleControl(Control ctl, float wScale, float hScale)
        {
            int ctrLeft0, ctrTop0, ctrWidth0, ctrHeight0;
            float ctrFontSize0;
           //第1个是窗体自身的 Left,Top,Width,Height,所以窗体控件从ctrlNo=1开始
            foreach (Control c in ctl.Controls)
            { 
                //获得控件原有的位置和大小信息
                ctrLeft0 = oldCtrl[ctrlNo].Left;
                ctrTop0 = oldCtrl[ctrlNo].Top;
                ctrWidth0 = oldCtrl[ctrlNo].Width;
                ctrHeight0 = oldCtrl[ctrlNo].Height;
                ctrFontSize0 = oldCtrl[ctrlNo].FontSize;
                //设置控件新的位置和大小信息。
                c.Left = (int)((ctrLeft0) * wScale);//新旧控件之间的线性比例。控件位置只相对于窗体
                c.Top = (int)((ctrTop0) * hScale);//
                c.Width = (int)(ctrWidth0 * wScale);//只与最初的大小相关,所以不能与现在的宽度相乘 
                c.Height = (int)(ctrHeight0 * hScale);//
                c.Font = new Font(c.Font.Name, (float)(ctrFontSize0 * wScale));//设置控件中字体的大小以适应控件的大小
                ctrlNo++;//累加序号
                //**放在这里,是先缩放控件本身,后缩放控件的子控件,重点是前后要一致(与保存时)
                if (c.Controls.Count > 0)
                    AutoScaleControl(c, wScale, hScale);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
            }
        }
    }
}
    代码中的注释比较详细了,如果你想实现窗体的自适应分辨率,你只需要在窗体的Layout事件中添加如下代码:
        /// <summary>
        /// 声明一个窗体自适应分辨率类
        /// </summary>
        public AutoSizeFormClass As = new AutoSizeFormClass();
        /// <summary>
        /// 在窗体的layout事件中调用
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Layout(object sender, LayoutEventArgs e)
        {
            As.controlAutoSize(this);
        }

    最后想说的是为什么用layout事件,不用Resize或者是SizeChanged事件,这个我查了好长时间,也自己试了所有的方法,但还是没能明白只是发现这几个事件的触发顺序是不同的首先触发的是Resize→然后是SizeChanged→然后是layout→最后是Load事件,是不是把适应分辨率的代码写在那个事件下都可以呢,这个我也尝试了,当窗体中含有tabcontrol控件时只有layout事件触发时才能检测出窗体中包含控件,这几个事件的区别我实在不知道有声明区别。希望读者给出帮助。

免责声明:文章转载自《WinForm窗体自适应分辨率》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇nmap加载nse脚本在内网渗透中的使用-上多种方式安装GitLabRunner下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

VC中使用Matlab Engine出现"无法找到libeng.dll"的问题

VC中使用Matlab Engine出现"无法找到libeng.dll"的问题 本以为使这个原因 ,其实不是我2了 #include "engine.h" //终于知道为什吗老是找不到那个库文件--是因为添加的头文件是以引号括起来的啊 //#include <engine.h> 不是因为环境变量没有生效的缘故 其实目前来说应该是这个问题no c...

RHEL7.1安装VNC

1.安装包 yum install vnc* -y 2.创建password vncserver 3.创建參数文件 [root@single ~]# cp /lib/systemd/system/vncserver@.service /lib/systemd/system/vncserver@:1.service 4.改动參数文件 [root@singl...

.net framework 2.0安装

要编译一个带shader的 xna程序 错误: 未能找到 .NET Framework SDK。该任务正在注册表项 localmachine\software\microsoft\.netframework 的 SDKInstallRootv2.0 值中指定的位置查找 .NET Framework SDK 的路径。您可以通过执行下列操作之一,来解决这一问题...

屏蔽文本框的粘贴操作(即,不允许从其他地方复制东西直接粘贴到该文本框中)

这个文本框一般都是输入身份证号码、输入密码等的文本框,是出于安全方面的考虑。 具体代码是向html代码的文本框代码属性中添加一个onpaste属性: //具体可以给HTML控件组中的Input(Text)控件添加此属性 <input id="Text1" type="text" onpaste="return false" name="textfie...

javascript“数组”的常用方法---以及冒泡排序

首先,数组是数据的集合。 可以通过构造函数(var arr = new Array('0','1','hello'))和字面量(var arr = ['0','1'])的方式来创建, 需要注意的是,构造函数创建时,如果值只有一个,而且还是数字,那么他代表数组的长度(var arr = new Array(5),创建一个长度为5的数组)。 数组的索引是从0开...

WPF快速指导7:控件和自定义控件

WPF快速指导7:控件和自定义控件 本文摘要: 1:控件和自定义控件的概念; 2:更改控件的外观; 3:自定义控件的设计原则; 1:控件和自定义控件的概念     Windows Presentation Foundation (WPF) 附带了许多几乎在所有 Windows 应用程序中都会使用的常见 UI 组件,如 Button、Label、TextBo...