最近公司要重构一个项目,把C++写的桌面应用改为winfrom,而此时我遇到一个问题就是winfrom控件的自动放大和缩小,就是根据窗口的大小来改变winfrom窗口和容器内的控件的大小。 在网上找了很多得到的效果并不如意,大多数都在介绍控件中的Anchor属性,但是这个属性会受各方面的影响,比如说容器,并不能达到自己想要的效果,后来在网上找到一段代码基本可以完成某些部分的放大和缩小,但是还是会出现一些问题:
- 当窗口最小化后重新打开窗口就会发生混乱
- 因为每个计算结果都是向上取整,也就是只要有小数点就会加一导致放大缩小后几次控件就会挤在一
- 如果将控件放在容器中就会发生混乱
为了解决这些问题,我对代码进行了部分修改如下所示:
注意!使用该类的时候每个控件的Anchor属性必须为None,AutoSize属性也必须为false,绝对不能设置MinimumSize和MaximumSize属性,否则窗口会在一定大小不再增大或缩小。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
namespace MainWindows
{
class AutoSizeFormClass
{
/// <summary>
/// 声明结构 记录控件位置和大小
/// </summary>
public struct ControlRect
{
public string name;
public float Left;
public float Top;
public float Width;
public float Height;
public float Size;
}
public List<ControlRect> _oldCtrl = new List<ControlRect>();
private int _ctrlNo = 0;
ControlRect decimals;
public void RenewControlRect(Control mForm)
{
//如果控件集合对象_oldCtrl不存在则将其添加,如果不添加首先无法找到主窗口
//也就无法开始遍历
ControlRect cR;
= ;
cR.Left = mForm.Left;
= mForm.Top;
cR.Width = mForm.Width;
cR.Height = mForm.Height;
cR.Size = mForm.Font.Size;
_oldCtrl.Add(cR);
AddControl(mForm);
_ctrlNo = 1;
}
private void AddControl(Control ctrl)
{
foreach (Control c in ctrl.Controls)
{
ControlRect cR;
= ;
cR.Left = c.Left;
= ;
cR.Width = c.Width;
cR.Height = c.Height;
cR.Size = c.Font.Size;
_oldCtrl.Add(cR);
// 控件可能嵌套子控件
if (c.Controls.Count > 0)
AddControl(c);
}
}
public void ControlAutoSize(Control mForm)
{
_ctrlNo = 1;
/*计算宽度比率*/
float wScale = (float)mForm.Width / _oldCtrl[0].Width;
/*计算高度比率*/
float hScale = (float)mForm.Height / _oldCtrl[0].Height;
AutoScaleControl(mForm, wScale, hScale);
}
private void AutoScaleControl(Control mForm, float wScale, float hScale)
{
float ctrlLeft, ctrlTop, ctrlWidth, ctrlHeight;
float ctrlFontSize, hSize, wSize;
List<ControlRect> Ctrl = new List<ControlRect>();
foreach (Control c in mForm.Controls)
{
//在_oldCtrl 中查询出控件名称相同的控件,并返回对象
ControlRect shortDigits = _oldCtrl.Where((p) => == ).ToList().FirstOrDefault();
//获取左边框的长度
ctrlLeft = shortDigits.Left;
//获取上边框的长度
ctrlTop = ;
//获取宽度
ctrlWidth = shortDigits.Width;
//获取高度
ctrlHeight = shortDigits.Height;
//获取字体大小
ctrlFontSize = shortDigits.Size;
//通过获取的比率相乘计算出要显示的x,y轴
c.Left = (int)Math.Round((ctrlLeft * wScale));
if(c.Left< 0) {
c.Left = 0;
}
= (int)Math.Round((ctrlTop * hScale));
if( < 0 ) {
= 0;
}
//保存计算结果后的坐标和大小,当下次进行计算是使用该浮点型进行计算
//确保控件不会错乱
//设置高度和宽度
c.Width = (int)Math.Round((ctrlWidth * wScale));
c.Height = (int)Math.Round((ctrlHeight * hScale));
//通过比率获取放大或缩小后的字体大小并进行设置
wSize = ctrlFontSize * wScale;
hSize = ctrlFontSize * hScale;
if (hSize < 7)
{
hSize = 7;
}
if (wSize < 7)
{
wSize = 7;
}
c.Font = new Font(c.Font.Name, Math.Min(hSize, wSize), c.Font.Style, c.Font.Unit);
_ctrlNo++;
// 先缩放控件本身 再缩放子控件
if (c.Controls.Count > 0)
{
AutoScaleControl(c, wScale, hScale);
}
= ctrlTop * hScale;
shortDigits.Left = ctrlTop * wScale;
shortDigits.Width = ctrlTop * wScale;
shortDigits.Height = ctrlTop * hScale;
//Ctrl.Add(shortDigits);
}
}
}
}
调用方式
调用方式如下所示:
注意!一定要用如下格式或者类似如下格式进行调用,否则出现错误
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MainWindows
{
public partial class Form1 : Form
{
AutoSizeFormClass asc = new AutoSizeFormClass();
public Form1()
{
InitializeComponent();
asc.RenewControlRect(this);
}
private void Form1_SizeChanged(object sender, EventArgs e)
{
asc.ControlAutoSize(this);
}
}
}