最近公司要重構一個項目,把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.name = mForm.Name;
cR.Left = mForm.Left;
cR.Top = 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.name = c.Name;
cR.Left = c.Left;
cR.Top = c.Top;
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) => p.name == c.Name).ToList().FirstOrDefault();
//獲取左邊框的長度
ctrlLeft = shortDigits.Left;
//獲取上邊框的長度
ctrlTop = shortDigits.Top;
//獲取寬度
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;
}
c.Top = (int)Math.Round((ctrlTop * hScale));
if(c.Top < 0 ) {
c.Top = 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);
}
shortDigits.Top = ctrlTop * hScale;
shortDigits.Left = ctrlTop * wScale;
shortDigits.Width = ctrlTop * wScale;
shortDigits.Height = ctrlTop * hScale;
//Ctrl.Add(shortDigits);
}
}
}
}