在做一項工程中,由於不確定目標平台的分辨率,而正常使用要求鋪滿整個屏幕,所以界面中的各個控件必須能夠適應窗口的變化。
首先想到的就是控件的百分比布局,但是再嘗試寫了幾個控件的Location和Size之后,發現這真是一項浩大的工程,方法是在太笨,不如將控件百分比布局作為一個類,專門來負責。
在網上找到了這種思想的代碼
http://blog.sina.com.cn/s/blog_45eaa01a0101c7ko.html
經過測試是能夠完成任務的,但是仍有一定的缺陷
1.我的界面中有控件動態的隱藏和可見,在這種情況下,該代碼縮放會造成控件位置混亂
2.不能沒有改變文字的大小。
為了適應我的項目需要,對他的代碼進行了一定的修改,修改后的代碼如下
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Windows.Forms; namespace SAR01 { class AutoSizeFormClass { //控件的初始位置信息。 public struct controlRect { public int Left; public int Top; public int Width; public int Height; } //存儲控件名和他的位置 public Dictionary<String, controlRect> oldCtrl = new Dictionary<String, controlRect>(); int ctrlNo = 0; //記錄窗體和其控件的初始位置和大小, public void controllInitializeSize(Control mForm) { controlRect cR; cR.Left = mForm.Left; cR.Top = mForm.Top; cR.Width = mForm.Width; cR.Height = mForm.Height; insertDictionary(mForm.Name, cR); AddControl(mForm);//窗體內其余控件還可能嵌套控件(比如panel),要單獨抽出,因為要遞歸調用 //this.WindowState = (System.Windows.Forms.FormWindowState)(2);//記錄完控件的初始位置和大小后,再最大化 //0 - Normalize , 1 - Minimize,2- Maximize } 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; insertDictionary(c.Name, objCtrl); if (c.Controls.Count > 0) AddControl(c); } } //(3.2)控件自適應大小, public void controlAutoSize(Control mForm) { if (ctrlNo == 0) { AddControl(mForm);//窗體內其余控件可能嵌套其它控件(比如panel),故單獨抽出以便遞歸調用 } float wScale = (float)mForm.Width / oldCtrl[mForm.Name].Width; ;//新舊窗體之間的比例,與最早的舊窗體 float hScale = (float)mForm.Height / oldCtrl[mForm.Name].Height; ;//.Height; ctrlNo = 1;//進入=1,第0個為窗體本身,窗體內的控件,從序號1開始 AutoScaleControl(mForm, wScale, hScale);//窗體內其余控件還可能嵌套控件(比如panel),要單獨抽出,因為要遞歸調用 } AutoScaleControl(mForm, wScale, hScale);//窗體內其余控件還可能嵌套控件(比如panel),要單獨抽出,因為要遞歸調用 } private void AutoScaleControl(Control ctl, float wScale, float hScale) { int ctrLeft0, ctrTop0, ctrWidth0, ctrHeight0; //int ctrlNo = 1;//第1個是窗體自身的 Left,Top,Width,Height,所以窗體控件從ctrlNo=1開始 foreach (Control c in ctl.Controls) { //**放在這里,是先縮放控件的子控件,后縮放控件本身 //if (c.Controls.Count > 0) // AutoScaleControl(c, wScale, hScale);//窗體內其余控件還可能嵌套控件(比如panel),要單獨抽出,因為要遞歸調用 ctrLeft0 = oldCtrl[c.Name].Left; ctrTop0 = oldCtrl[c.Name].Top; ctrWidth0 = oldCtrl[c.Name].Width; ctrHeight0 = oldCtrl[c.Name].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);// AutoScaleFont(c); ctrlNo++;//累加序號 //**放在這里,是先縮放控件本身,后縮放控件的子控件 if (c.Controls.Count > 0) AutoScaleControl(c, wScale, hScale);//窗體內其余控件還可能嵌套控件(比如panel),要單獨抽出,因為要遞歸調用 } } private void AutoScaleFont(Control c) { string[] type = c.GetType().ToString().Split('.'); string controlType = type[type.Length - 1]; switch (controlType) { //case "Button": // c.Font = new System.Drawing.Font("宋體", c.Height * 0.4f); // break; case "GroupBox": c.Font = new System.Drawing.Font("宋體", c.Height * 0.04f); break; } }
private void insertDictionary(String name,controlRect cr) //添加控件名和位置,如果名稱重復則更新 { Dictionary<String, controlRect> temp = new Dictionary<String, controlRect>(); bool flag = false; foreach (var pair in oldCtrl) { if (pair.Key.ToString() == name) { temp.Add(name, cr); flag = true; } } if (flag==false) { oldCtrl.Add(name, cr); } foreach (var value in temp) { oldCtrl.Remove(value.Key.ToString()); oldCtrl.Add(value.Key,value.Value); } temp.Clear(); } } }
/////////////////////////////////////////////下面是需要自適應的窗體///////////////////////////////////////////////
using System;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
//1.聲明自適應類實例
AutoSizeFormClass asc = new AutoSizeFormClass();
public Form1()
{
InitializeComponent();
//如果加入"皮膚",則不能在Form1_Load中記錄控件的大小和位置,因為有些控件如dataGridView的子控件還未完成
//而要在在Form1_SizeChanged中,第一次改變時,記錄控件的大小和位置
this.skinEngine1.SkinFile = "EmeraldColor1.ssk";
}
//2. 為窗體添加Load事件,並在其方法Form1_Load中,調用類的初始化方法,記錄窗體和其控件的初始位置和大小
private void Form1_Load(object sender, EventArgs e)
{
// asc.controllInitializeSize(this);
}
//3.為窗體添加SizeChanged事件,並在其方法Form1_SizeChanged中,調用類的自適應方法,完成自適應
private void Form1_SizeChanged(object sender, EventArgs e)
{
asc.controlAutoSize(this);
// this.WindowState = (System.Windows.Forms.FormWindowState)(2);//記錄完控件的初始位置和大小后,再最大化
}
}
}