WinForm窗体自适应分辨率
我們自己編寫程序的界面,會(huì)遇到各種屏幕分辨率,只有自適應(yīng)才能顯的美觀。實(shí)際上,做到這點(diǎn)也很簡(jiǎn)單,就是首先記錄窗體和它上面控件的初始位置和大小,當(dāng)窗體改變比例時(shí),其控件的位置和大小也按此比例變化即可。因?yàn)榇绑w上控件的位置和大小是相對(duì)于自己所在的窗體的,也就是所謂的窗口坐標(biāo)。??
在這里我們只考慮相對(duì)于自己窗體的窗口坐標(biāo)更簡(jiǎn)單,也就是成比例變化。為了多個(gè)窗體共用,我在這里創(chuàng)建一個(gè)類AutoSizeFormClass ,1.使用它去記錄窗體和其控件的初始位置和大小,2.判斷窗體中的控件是否為容器控件,如果是記錄容器控件中的控件的初始位置和大小3.根據(jù)窗體變化了的大小,成比例地實(shí)現(xiàn)其控件的水平和垂直方向的變化,也就是自適應(yīng)。?
二。使用方法
使用方法很簡(jiǎn)單,
1.把自適應(yīng)的類整體復(fù)制到你的工程命名空間里,
???然后在需要自適應(yīng)的窗體中做2步即可:
2.聲明自適應(yīng)類實(shí)例。
3.為窗體添加大小改變事件,并在其方法中,調(diào)用類的自適應(yīng)方法,完成自適應(yīng) 通過上面的介紹我們會(huì)發(fā)現(xiàn)其中的幾個(gè)實(shí)現(xiàn)難點(diǎn): 1.如何保存窗體的以及其中控件的位置以及大小等屬性,當(dāng)然我們最常用的方法就是自己定義一個(gè)實(shí)體,實(shí)體中包含我們需要保持的屬性(主要包括left,top,width,height,以及fontsize屬性)這個(gè)我提供的解決方案是定義一個(gè)數(shù)據(jù)結(jié)構(gòu)。 普及一下結(jié)構(gòu)體的知識(shí):結(jié)構(gòu)體中包含其中要存儲(chǔ)的數(shù)據(jù),使用結(jié)構(gòu)體的好處在于可以將不同類型的數(shù)據(jù)有序的組合在一起,結(jié)構(gòu)造出一個(gè)新的數(shù)據(jù)類型,不占內(nèi)存空間,只用定義結(jié)構(gòu)體的變量時(shí)才開辟內(nèi)存空間,結(jié)構(gòu)體類型的變量在內(nèi)存依照其成員順序順序排列,所占內(nèi)存空間的大小是其全體成員所占空間的總和,結(jié)構(gòu)體可以作為函數(shù)的參數(shù),函數(shù)也可以返回結(jié)構(gòu)體。 看我們定義的結(jié)構(gòu)體: /// <summary>/// 聲明一個(gè)結(jié)構(gòu),用于保存控件位置的基本屬性。/// </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;}
?
? ? 然后聲明一個(gè)泛型用來保存所有控件位置以及大小信息產(chǎn)生的結(jié)構(gòu)體信息。 //這里只是列出兩個(gè)容器控件分別為panel控件和groupbox控件if (c.GetType().ToString() == "System.Windows.Forms.Panel"){//要執(zhí)行的代碼 }//如果是GroupBox控件if (c.GetType().ToString() == "System.Windows.Forms.GroupBox"){//要執(zhí)行的代碼}?
? ??但我發(fā)現(xiàn)自己很難把所有的控件都想全了,即使是想全了也會(huì)重復(fù)太多的代碼,最后采取了一個(gè)很有效的方法就是加上這個(gè)判斷:
??????????? if (c.Controls.Count > 0)
??? 一旦這個(gè)判斷成立就說明這個(gè)控件就是一個(gè)容器控件了。
問題3.遞歸調(diào)用保存控件信息類,實(shí)現(xiàn)所有控件(包括容器控件)的位置和大小信息的保存。
?
?
???問題4.如何保存畫窗體時(shí)窗體的大小,聽起來有些別嘴,其實(shí)也可以說是你想要窗體呈現(xiàn)的大小,這個(gè)大大家好像會(huì)有疑問但雖然說窗體是控件的一種,但是進(jìn)過我的實(shí)現(xiàn),當(dāng)我們改變分辨率的同時(shí),比如我們?cè)瓉碓O(shè)置窗體每次打開時(shí)最大化顯示,但是無論我們編寫程序時(shí)設(shè)置的窗體的大小多大,我們運(yùn)行起來時(shí)窗體都會(huì)占滿整個(gè)屏幕,這也是出現(xiàn)由于分辨率改變,大窗體中部分控件無法顯示完全的原因。比如我們的做的這個(gè)很大的登陸界面,看看效果:
??????? 小分辨率下的情況:
? ? ? ?大分辨率下應(yīng)該是這樣:
?
?我們會(huì)發(fā)現(xiàn)窗體最大化了。但是窗體中的控件沒有跟上。 說了這么多我想大家都迫不及待的想看代碼了: 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>/// 聲明一個(gè)結(jié)構(gòu),用于保存控件位置的基本屬性。/// </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>/// 聲明一個(gè)泛型,類型為什么的保存控件屬性的結(jié)構(gòu)類,/// </summary>public List<controlRect> oldCtrl = new List<controlRect>();int ctrlNo = 0;//初始化標(biāo)識(shí)控件的變量為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);//**放在這里,是先記錄控件本身,后記錄控件的子控件,重點(diǎn)是前后要一致if (c.Controls.Count > 0)AddControl(c);//窗體內(nèi)其余控件還可能嵌套控件(比如panel),要單獨(dú)抽出,因?yàn)橐f歸調(diào)用 }}/// <summary>/// 窗體自適應(yīng)分辨率類/// </summary>/// <param name="mForm">需要進(jìn)行設(shè)置的窗體</param>public void controlAutoSize(Control mForm){if (ctrlNo == 0){ //*如果在窗體的Form1_Load中,記錄控件原始的大小和位置,正常沒有問題,但要加入皮膚就會(huì)出現(xiàn)問題,因?yàn)橛行┛丶鏳ataGridView的的子控件還沒有完成,個(gè)數(shù)少//*要在窗體的Form1_SizeChanged中,第一次改變大小時(shí),記錄控件原始的大小和位置,這里所有控件的子控件都已經(jīng)形成 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);//第一個(gè)為"窗體本身",只加入一次即可 AddControl(mForm);//窗體內(nèi)其余控件可能嵌套其它控件(比如panel),故單獨(dú)抽出以便遞歸調(diào)用 }float wScale = (float)mForm.Width / (float)oldCtrl[0].Width;//新舊窗體之間的比例,與最早的舊窗體比較float hScale = (float)mForm.Height / (float)oldCtrl[0].Height;//.Height;ctrlNo = 1;//進(jìn)入=1,第0個(gè)為窗體本身,窗體內(nèi)的控件,從序號(hào)1開始AutoScaleControl(mForm, wScale, hScale);//窗體內(nèi)其余控件還可能嵌套控件(比如panel),要單獨(dú)抽出,因?yàn)橐f歸調(diào)用 }/// 設(shè)置控件的屬性/// </summary>/// <param name="ctl">需要設(shè)置的控件</param>/// <param name="wScale">調(diào)整的高度比例</param>/// <param name="hScale">調(diào)整的寬度比例</param>private void AutoScaleControl(Control ctl, float wScale, float hScale){int ctrLeft0, ctrTop0, ctrWidth0, ctrHeight0;float ctrFontSize0;//第1個(gè)是窗體自身的 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;//設(shè)置控件新的位置和大小信息。c.Left = (int)((ctrLeft0) * wScale);//新舊控件之間的線性比例??丶恢弥幌鄬?duì)于窗體c.Top = (int)((ctrTop0) * hScale);// c.Width = (int)(ctrWidth0 * wScale);//只與最初的大小相關(guān),所以不能與現(xiàn)在的寬度相乘 c.Height = (int)(ctrHeight0 * hScale);// c.Font = new Font(c.Font.Name, (float)(ctrFontSize0 * wScale));//設(shè)置控件中字體的大小以適應(yīng)控件的大小ctrlNo++;//累加序號(hào)//**放在這里,是先縮放控件本身,后縮放控件的子控件,重點(diǎn)是前后要一致(與保存時(shí))if (c.Controls.Count > 0)AutoScaleControl(c, wScale, hScale);//窗體內(nèi)其余控件還可能嵌套控件(比如panel),要單獨(dú)抽出,因?yàn)橐f歸調(diào)用 }}} }代碼中的注釋比較詳細(xì)了,如果你想實(shí)現(xiàn)窗體的自適應(yīng)分辨率,你只需要在窗體的Layout事件中添加如下代碼:/// <summary>/// 聲明一個(gè)窗體自適應(yīng)分辨率類/// </summary>public AutoSizeFormClass As = new AutoSizeFormClass();/// <summary>/// 在窗體的layout事件中調(diào)用/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Form1_Layout(object sender, LayoutEventArgs e){As.controlAutoSize(this);}?
? ? 最后想說的是為什么用layout事件,不用Resize或者是SizeChanged事件,這個(gè)我查了好長(zhǎng)時(shí)間,也自己試了所有的方法,但還是沒能明白只是發(fā)現(xiàn)這幾個(gè)事件的觸發(fā)順序是不同的首先觸發(fā)的是Resize→然后是SizeChanged→然后是layout→最后是Load事件,是不是把適應(yīng)分辨率的代碼寫在那個(gè)事件下都可以呢,這個(gè)我也嘗試了,當(dāng)窗體中含有tabcontrol控件時(shí)只有l(wèi)ayout事件觸發(fā)時(shí)才能檢測(cè)出窗體中包含控件,這幾個(gè)事件的區(qū)別我實(shí)在不知道有聲明區(qū)別。希望讀者給出幫助。
轉(zhuǎn)載于:https://www.cnblogs.com/CandiceW/p/4226711.html
總結(jié)
以上是生活随笔為你收集整理的WinForm窗体自适应分辨率的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 遍历窗体中所有控件的信息
- 下一篇: // D:\SaveLog\_SaveL