WindowsMobile/Win Form-界面自适应
起因
??? 使用SmartPhone上的WinForm做了一個(gè)WM的小程序,結(jié)果放到手機(jī)上實(shí)際一運(yùn)行。發(fā)現(xiàn)動(dòng)態(tài)生成的控件在里面顯示得都非常小,難以看清。
原因
??? 我的問(wèn)題是需要在InitializeComponent方法結(jié)束后,動(dòng)態(tài)生成一些控件,如下:
/// <summary> /// 這個(gè)方法會(huì)根據(jù)傳入的實(shí)體模型,生成一些選擇框,設(shè)置它們的大小、位置;并會(huì)改變其它控件的大小、位置。 /// </summary> /// <param name="categories"></param> private void GenerateCheckBoxes(IList<Category> categories) { …… }??? 原因就是因?yàn)槭謾C(jī)分辨率較大,而這些動(dòng)態(tài)生成的控件并沒(méi)有進(jìn)行隨著分辨率不同而進(jìn)行自動(dòng)縮放。而由界面設(shè)計(jì)器設(shè)計(jì)出來(lái)的控件,都能很好的顯示。
求索
??? 由于界面生成的控件能夠很好的自適應(yīng)分辨率的不同,所以先看一下Designer生成的代碼:
private void InitializeComponent() {this.BAdd = new System.Windows.Forms.Button();this.PCategories = new System.Windows.Forms.Panel();this.SuspendLayout(); // BAddthis.BAdd.Location = new System.Drawing.Point(165, 164);this.BAdd.Name = "BAdd";this.BAdd.Size = new System.Drawing.Size(72, 20);this.BAdd.TabIndex = 11;this.BAdd.Text = "Add";this.BAdd.Click += new System.EventHandler(this.BAdd_Click); // PCategoriesthis.PCategories.Location = new System.Drawing.Point(73, 83);this.PCategories.Name = "PCategories";this.PCategories.Size = new System.Drawing.Size(164, 75); // MainFormthis.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;this.AutoScroll = true;this.ClientSize = new System.Drawing.Size(243, 258);this.Controls.Add(this.PCategories);this.Controls.Add(this.BAdd);this.Name = "MainForm";this.Text = "MoneyManagerForm";this.ResumeLayout(false); }??? 這里的重點(diǎn)是使用了AutoScaleDimensions和AutoScaleMode屬性來(lái)設(shè)置界面為自動(dòng)縮放。(Dpi表示Dot per inch,WPF就是直接使用這種方式來(lái)控制界面的。)然后最后一步調(diào)用ResumeLayout方法,這個(gè)方法中,會(huì)調(diào)用到ContainerControl.PerformAutoScale方法進(jìn)行自動(dòng)縮放。
??? 最可惡的一點(diǎn):從控件的構(gòu)造,到界面的自動(dòng)縮放,全部在一個(gè)方法中實(shí)現(xiàn)!而且這個(gè)方法中,沒(méi)有什么好的辦法來(lái)調(diào)用我生成控件的方法……
解決過(guò)程
??? 在Form中,重寫(xiě)ScaleControl方法如下:
protected override void ScaleControl(SizeF factor, BoundsSpecified specified) {var categories = Config.Instance.Categories;this.GenerateCheckBoxes(categories);base.ScaleControl(factor, specified); }??? 因?yàn)檎{(diào)用過(guò)程是這樣的:
??? Control.LayoutResume() –> ContainerControl.PerformAutoScale() –> Control.Scale() –> Control.ScaleControl() & Control.ScaleChildControls()。
??? 所以,只需要重寫(xiě)這個(gè)方法,就可以在真正執(zhí)行自動(dòng)縮放所有控件前,先把動(dòng)態(tài)控件生成。
??? 不過(guò),這樣做同樣有局限性:因?yàn)檫@里是在InitializeComponent方法中進(jìn)行PerformAutoScale,所以這里的這些動(dòng)態(tài)生成的控件,其實(shí)是在應(yīng)用程序的開(kāi)始階段就已經(jīng)被明確了。相反,如果在運(yùn)行一段時(shí)間后,需要想再動(dòng)態(tài)生成其它控件,就不能使用這個(gè)方法了。那時(shí),就需要直接調(diào)用剛生成的需要縮放的控件的Scale方法。而且不能直接使用PerformAutoScale方法了,因?yàn)橐WC一個(gè)控件只被調(diào)用Scale方法一次! 在這里,只需要這樣簡(jiǎn)單實(shí)現(xiàn)就行了。:)
??? 另外,一開(kāi)始以為PerformAutoScale并不會(huì)把縮放過(guò)的控件,再縮放一次,結(jié)果就寫(xiě)成了這樣的錯(cuò)誤方案:
public MainForm() {InitializeComponent();//暫停布局 this.SuspendLayout(); //在InitComponents調(diào)用的PerformAutoScale方法里面,最后會(huì)把這個(gè)數(shù)給置為運(yùn)行時(shí)的數(shù)據(jù)。所以這里需要重新設(shè)置。 this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //生成控件this.GenerateCategories();//自動(dòng)縮放this.PerformAutoScale();//其實(shí)這里會(huì)把InitializeComponent中縮放的控件都再縮放一遍。//繼續(xù)布局this.ResumeLayout(false); }
結(jié)束語(yǔ)
??? 其實(shí),這里的自動(dòng)縮放過(guò)程,在WinForm開(kāi)發(fā)中,也是一樣的。
??? 而且這次實(shí)踐中,我還發(fā)現(xiàn):我在Win7的系統(tǒng)上隨手點(diǎn)了一下這個(gè)程序,居然所有功能都能夠正常的運(yùn)行……汗,當(dāng)時(shí)做的時(shí)候,可是專(zhuān)門(mén)為WindowsMobile開(kāi)發(fā)的窗體啊。這個(gè)“跨平臺(tái)”功能,確實(shí)很強(qiáng)大,著實(shí)讓我吃驚不小。
??? 另外,由于VS2008自帶的模擬器的屏幕分辨率和設(shè)計(jì)時(shí)的分辨率是一樣大的,而我手機(jī)的分辨率比這個(gè)要大得多。所以每次調(diào)試這個(gè)縮放過(guò)程時(shí),都要生成好了,然后拷貝到手機(jī)上看效果,真是吐血……
?
?
?
引用
Windows 窗體中的自動(dòng)縮放
自動(dòng)縮放的執(zhí)行過(guò)程
Windows 窗體現(xiàn)在使用下面的邏輯自動(dòng)對(duì)窗體及其內(nèi)容進(jìn)行縮放:
設(shè)計(jì)時(shí),每一個(gè) ContainerControl 分別在 AutoScaleMode 和 AutoScaleDimensions 中記錄縮放模式和它的當(dāng)前分辨率。
運(yùn)行時(shí),實(shí)際分辨率存儲(chǔ)在 CurrentAutoScaleDimensions 屬性中。AutoScaleFactor 屬性會(huì)動(dòng)態(tài)計(jì)算運(yùn)行時(shí)分辨率與設(shè)計(jì)時(shí)分辨率的比值。
當(dāng)加載窗體時(shí),如果 CurrentAutoScaleDimensions 和 AutoScaleDimensions 的值不同,則會(huì)調(diào)用 PerformAutoScale 方法對(duì)該控件及其子控件進(jìn)行縮放。此方法會(huì)掛起布局并調(diào)用 Scale 方法執(zhí)行實(shí)際縮放。然后,會(huì)更新 AutoScaleDimensions 值以避免累進(jìn)縮放。
在下面的情況下還會(huì)自動(dòng)調(diào)用 PerformAutoScale:
-
在縮放模式為 Font 時(shí)響應(yīng) OnFontChanged 事件。
-
當(dāng)繼續(xù)執(zhí)行容器控件的布局時(shí)檢測(cè)到 AutoScaleDimensions 或 AutoScaleMode 屬性發(fā)生更改。
-
與上面的情況類(lèi)似,檢測(cè)到父 ContainerControl 正在被縮放。每個(gè)容器控件只負(fù)責(zé)使用自己的比例因子縮放自己的子控件,并不負(fù)責(zé)縮放其父容器中的控件。
子控件可以通過(guò)下面的若干方式修改其縮放行為:
-
可以重寫(xiě) ScaleChildren 屬性以確定是否應(yīng)縮放其子控件。
-
可以重寫(xiě) GetScaledBounds 方法以調(diào)整要將控件縮放至的邊界,但不調(diào)整縮放邏輯。
-
可以重寫(xiě) ScaleControl 方法以更改當(dāng)前控件的縮放邏輯。
總結(jié)
以上是生活随笔為你收集整理的WindowsMobile/Win Form-界面自适应的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 常用SVN地址
- 下一篇: 周鸿祎的“加法”和“减法”