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

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

  1. /// <summary>
  2. /// 声明一个结构,用于保存控件位置的基本属性。
  3. /// </summary>
  4. public struct controlRect
  5. {
  6. /// <summary>
  7. /// 控件的left属性
  8. /// </summary>
  9. public int Left;
  10. /// <summary>
  11. /// 控件的Right属性
  12. /// </summary>
  13. public int Top;
  14. /// <summary>
  15. /// 控件的Weight属性
  16. /// </summary>
  17. public int Width;
  18. /// <summary>
  19. /// 控件的High属性
  20. /// </summary>
  21. public int Height;
  22. /// <summary>
  23. /// 控件的Fontsize属性
  24. /// </summary>
  25. public float FontSize;
  26. }

然后声明一个泛型用来保存所有控件位置以及大小信息产生的结构体信息。

  1. //这里只是列出两个容器控件分别为panel控件和groupbox控件
  2. if (c.GetType().ToString() == "System.Windows.Forms.Panel")
  3. {
  4. //要执行的代码
  5. }
  6. //如果是GroupBox控件
  7. if (c.GetType().ToString() == "System.Windows.Forms.GroupBox")
  8. {
  9. //要执行的代码
  10. }
 

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

if (c.Controls.Count > 0)

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

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

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

小分辨率下的情况:

大分辨率下应该是这样:

        ​我们会发现窗体最大化了。但是窗体中的控件没有跟上。
        说了这么多我想大家都迫不及待的想看代码了:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows.Forms;
  6. using System.Drawing;
  7. namespace AutoSizeFormClass
  8. {
  9. public class AutoSizeFormClass
  10. {
  11. /// <summary>
  12. /// 声明一个结构,用于保存控件位置的基本属性。
  13. /// </summary>
  14. public struct controlRect
  15. {
  16. /// <summary>
  17. /// 控件的left属性
  18. /// </summary>
  19. public int Left;
  20. /// <summary>
  21. /// 控件的Right属性
  22. /// </summary>
  23. public int Top;
  24. /// <summary>
  25. /// 控件的Weight属性
  26. /// </summary>
  27. public int Width;
  28. /// <summary>
  29. /// 控件的High属性
  30. /// </summary>
  31. public int Height;
  32. /// <summary>
  33. /// 控件的Fontsize属性
  34. /// </summary>
  35. public float FontSize;
  36. }
  37. /// <summary>
  38. /// 声明一个泛型,类型为什么的保存控件属性的结构类,
  39. /// </summary>
  40. public List<controlRect> oldCtrl = new List<controlRect>();
  41. int ctrlNo = ;//初始化标识控件的变量为0,表示窗体本身。
  42. /// <summary>
  43. /// 保存控件的位置和大小信息
  44. /// </summary>
  45. /// <param name="ctl">需要被保存的控件</param>
  46. private void AddControl(Control ctl)
  47. {
  48. foreach (Control c in ctl.Controls)
  49. {
  50. controlRect objCtrl;
  51. objCtrl.Left = c.Left;
  52. objCtrl.Top = c.Top;
  53. objCtrl.Width = c.Width;
  54. objCtrl.Height = c.Height;
  55. objCtrl.FontSize = c.Font.Size;
  56. oldCtrl.Add(objCtrl);
  57. //**放在这里,是先记录控件本身,后记录控件的子控件,重点是前后要一致
  58. if (c.Controls.Count > )
  59. AddControl(c);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
  60. }
  61. }
  62. /// <summary>
  63. /// 窗体自适应分辨率类
  64. /// </summary>
  65. /// <param name="mForm">需要进行设置的窗体</param>
  66. public void controlAutoSize(Control mForm)
  67. {
  68. if (ctrlNo == )
  69. { //*如果在窗体的Form1_Load中,记录控件原始的大小和位置,正常没有问题,但要加入皮肤就会出现问题,因为有些控件如dataGridView的的子控件还没有完成,个数少
  70. //*要在窗体的Form1_SizeChanged中,第一次改变大小时,记录控件原始的大小和位置,这里所有控件的子控件都已经形成
  71. controlRect cR;
  72. cR.Left = mForm.Left;
  73. cR.Top = mForm.Top;
  74. cR.Width = mForm.Width;
  75. cR.Height = mForm.Height;
  76. cR.Width = int.Parse(mForm.Tag.ToString().Split(',')[]);
  77. cR.Height = int.Parse(mForm.Tag.ToString().Split(',')[]);
  78. cR.FontSize = mForm.Font.Size;
  79. oldCtrl.Add(cR);//第一个为"窗体本身",只加入一次即可
  80. AddControl(mForm);//窗体内其余控件可能嵌套其它控件(比如panel),故单独抽出以便递归调用
  81. }
  82. float wScale = (float)mForm.Width / (float)oldCtrl[].Width;//新旧窗体之间的比例,与最早的旧窗体比较
  83. float hScale = (float)mForm.Height / (float)oldCtrl[].Height;//.Height;
  84. ctrlNo = ;//进入=1,第0个为窗体本身,窗体内的控件,从序号1开始
  85. AutoScaleControl(mForm, wScale, hScale);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
  86. }
  87. /// 设置控件的属性
  88. /// </summary>
  89. /// <param name="ctl">需要设置的控件</param>
  90. /// <param name="wScale">调整的高度比例</param>
  91. /// <param name="hScale">调整的宽度比例</param>
  92. private void AutoScaleControl(Control ctl, float wScale, float hScale)
  93. {
  94. int ctrLeft0, ctrTop0, ctrWidth0, ctrHeight0;
  95. float ctrFontSize0;
  96. //第1个是窗体自身的 Left,Top,Width,Height,所以窗体控件从ctrlNo=1开始
  97. foreach (Control c in ctl.Controls)
  98. {
  99. //获得控件原有的位置和大小信息
  100. ctrLeft0 = oldCtrl[ctrlNo].Left;
  101. ctrTop0 = oldCtrl[ctrlNo].Top;
  102. ctrWidth0 = oldCtrl[ctrlNo].Width;
  103. ctrHeight0 = oldCtrl[ctrlNo].Height;
  104. ctrFontSize0 = oldCtrl[ctrlNo].FontSize;
  105. //设置控件新的位置和大小信息。
  106. c.Left = (int)((ctrLeft0) * wScale);//新旧控件之间的线性比例。控件位置只相对于窗体
  107. c.Top = (int)((ctrTop0) * hScale);//
  108. c.Width = (int)(ctrWidth0 * wScale);//只与最初的大小相关,所以不能与现在的宽度相乘
  109. c.Height = (int)(ctrHeight0 * hScale);//
  110. c.Font = new Font(c.Font.Name, (float)(ctrFontSize0 * wScale));//设置控件中字体的大小以适应控件的大小
  111. ctrlNo++;//累加序号
  112. //**放在这里,是先缩放控件本身,后缩放控件的子控件,重点是前后要一致(与保存时)
  113. if (c.Controls.Count > )
  114. AutoScaleControl(c, wScale, hScale);//窗体内其余控件还可能嵌套控件(比如panel),要单独抽出,因为要递归调用
  115. }
  116. }
  117. }
  118. }
  119. 代码中的注释比较详细了,如果你想实现窗体的自适应分辨率,你只需要在窗体的Layout事件中添加如下代码:
  120. /// <summary>
  121. /// 声明一个窗体自适应分辨率类
  122. /// </summary>
  123. public AutoSizeFormClass As = new AutoSizeFormClass();
  124. /// <summary>
  125. /// 在窗体的layout事件中调用
  126. /// </summary>
  127. /// <param name="sender"></param>
  128. /// <param name="e"></param>
  129. private void Form1_Layout(object sender, LayoutEventArgs e)
  130. {
  131. As.controlAutoSize(this);
  132. }

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

WinForm窗体自适应分辨率的更多相关文章

  1. Winform 窗体自适应

    前言 在使用 Winform 开发过程中,经常发些因为显示器分辨率.窗体大小改变,控件却不能自适应变化,几经查找资料,和大佬的代码.经过细小修改,终于可以让窗体在外界影响下,窗体内背景图片.控件都会自 ...

  2. (C#)找的winform窗体自适应类

    原文:https://www.cnblogs.com/gguozhenqian/p/4288451.html 需要添加引用System.Windows.Forms public class AutoS ...

  3. winform窗体自适应大小

    1.添加一个类class AutoSizeFormClass { //(1).声明结构,只记录窗体和其控件的初始位置和大小. public struct controlRect { public in ...

  4. WPF窗体自适应分辨率

    使用WPF创建一个窗体(Window)时,如果设置了固定的高度(Height)和宽度(Width),一旦用户的电脑分辨率过低,就会使得窗体及其中的内容无法完整地显示出来.要解决这个这个问题,有以下几个 ...

  5. Winform窗体控件自适应大小

    自己写的winform窗体自适应大小代码,代码比较独立,很适合贴来贴去不会对原有程序造成影响,可以直接继承此类或者把代码复制到自己的代码里面直接使用 借鉴了网上的一些资料,最后采用重写WndProc方 ...

  6. C# WinForm窗体及其控件自适应各种屏幕分辨率

    C# WinForm窗体及其控件自适应各种屏幕分辨率 一.说明  我们自己编写程序的界面,会遇到各种屏幕分辨率,只有自适应才能显的美观.实际上,做到这点也很简单,就是首先记录窗体和它上面控件的初始位置 ...

  7. WinForm窗体及其控件的自适应

    3步骤: 1.在需要自适应的Form中实例化全局变量   AutoSizeFormClass.cs源码在下方 AutoSizeFormClass asc = new AutoSizeFormClass ...

  8. 转:C# WinForm窗体及其控件的自适应

    一.说明 2012-11-30 曾经写过 <C# WinForm窗体及其控件自适应各种屏幕分辨率>  ,其中也讲解了控件自适应的原理.近期有网友说,装在panel里面的控件,没有效果? 这 ...

  9. Delphi:窗体自适应屏幕分辨率的改进

    在窗体依据屏幕分辨率自适应调整尺度方面,昨天的工作可以说是一个突破点.昨天的工作找到了长期以来我的原有方案的问题所在,这是非常关键的.但是昨天晚上的解决方案并不完美,今天的这个才是比较完美的解决版. ...

随机推荐

  1. python如何序列化json数据

    使用json模块提供的loads方法和dumps方法,可以很方便的载入和读取json数据格式.而在具体实际应用中,我们使用python数据格式是 string.list 或dict等,这类格式如何直接 ...

  2. python之路----面向对象中的内置函数

    property属性 什么是特性property property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值 例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法 ...

  3. Web前端学习笔记之安装和使用PhantomJS

    0x00 安装PhantomJS(linux环境安装) 将PhantomJS下载在/usr/local/src/packet/目录下(这个看个人喜好) 操作系统:CentOS 7 64-bit 1.下 ...

  4. finedb(内置的HSQL数据库)迁移数据到MySQL

    finedb(内置的HSQL数据库)迁移数据到MySQL 1. 前言 在FineBI中,决策平台的数据(用户.角色.组织机构.权限等信息)是存储在finedb数据库中的,默认情况下finedb是一个内 ...

  5. 如何在 Linux 中挂载 ISO 文件

    在 Windows 中,我们常常使用 Daemon Tools 和 Virtual CloneDrive 等虚拟光驱软件挂载光盘镜像,下面我们一起来学习在 Linux 中如何挂载 ISO 文件. 在 ...

  6. 20145221高其_PC平台逆向破解_advanced

    20145221高其_PC平台逆向破解_advanced 实践目录 shellcode注入 Return-to-libc 攻击实验 shellcode注入 概述 Shellcode实际是一段代码(也可 ...

  7. STM32.BOOT

    BOOT0 和 BOOT1STM32 三种启动模式对应的存储介质均是芯片内置的,它们是:1)用户闪存 = 芯片内置的?Flash.2)SRAM = 芯片内置的 RAM 区,就是内存啦.3)系统存储器 ...

  8. vijos 1360 八数码问题 - 启发式搜索

    背景 Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们. 描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0 ...

  9. Python3基础 file seek 将文件的指针恢复到初始位置

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  10. Effective TensorFlow Chapter 4: TensorFlow中的广播Broadcast机制【转】

    本文转载自:https://blog.csdn.net/LoseInVain/article/details/78763303 TensorFlow支持广播机制(Broadcast),可以广播元素间操 ...