Windows窗口自動縮放機制


通過自動縮放功能,能使在一個計算機上設計的界面在另一個具有不同分辨率或系統字體的計算機上能正常顯示。這樣窗體及其控件就能通過智能化調整大小以保障在本地電腦和用戶電腦上保持一致。

自動縮放的必要性

如果沒有自動縮放功能,當改變顯示分辨率或字體時,其對應的應用不是顯得太大,就是顯得太小。例如,為Tahoma 9 point字體設計的程序,在系統字體為Tahoma 12 point的計算機上運行時,如果不對它進行任何調整,該應用程序就會顯得很小。其呈現的文本 與其他應用程序相比都要小一些。此外,包含文本的UI元素的大小也與使用的字體相關,此時這些元素也會顯得相對小些。

如果程序是針對某種分辨率設計的,也會發生類似情況。最常見的顯示分辨率為96DPI(dots per inch),按時高分辨率的顯示器如120、133、170也越來越多。如果應用不隨着分辨率調整,大小顯示也會不正常。

自動縮放即根據相對字體大小或分辨率來對窗體及其控件的大小進行調整。Windows操作系統能使用一種稱為對話框單位(dialog units)的相對單位,對對話框進行自動縮放。對話框單位基於系統字體,它與像素的關系可以通過Win32 SDK的GetDialogBaseUnits函數確定。當用戶改變了Windows使用的主題,所有的對話框都會自動調整對話框。另外,.NET框架能根據默認系統字體會顯示分辨率自動縮放。當然,也可以禁用自動縮放。

最早對自動縮放的支持

.NET 1.0和1.1 采用一種很直接的方法實現自動縮放,該方法依賴於UI使用的Windows默認字體,該字體由Win32 SDK的DEFAULT_GUI_FONT表示。通常只有在顯示分辨率改變時,該字體才會改變。下面的機制用於實現自動縮放:

  1. 設計時,AutoScaleBaseSize屬性(已被廢棄)被設置為本地電腦上默認系統字體的高度和寬度。
  2. 運行時,使用用戶電腦上的默認系統字體初始化Form類的Font屬性。
  3. 在窗體顯示前,調用ApplyAutoScaling方法縮放form。該方法先計算AutoScaleBaseSizeFont的相對大小,然后調用Scale方法實現form及其組件的縮放。
  4. 因為AutoScaleBaseSize的值已經更新,所以之后調用ApplyAutoScaling不再調整窗口。

該機制可滿足大部分需求,但它還有以下缺陷:

  • 因為AutoScaleBaseSize將baseline字體大小表示為整數值,所以某個窗體在經過多次分辨率更改后,其收入誤差會越來越大。
  • 盡在Form類中實現了自動調整,而ContainerControl中沒有。所以只有在用戶控件與窗體在相同的分辨率下進行設計,並在設計階段將控件放入窗體,用戶控件才能正確縮放。
  • 只有在大家的計算機分辨率都相同的情況下,才能同時設計窗體及其子控件。並且還會使窗體的繼承依賴於與父窗體關聯的分辨率。
  • 和.NET 2.0中引入的布局管理器(FlowLayoutPanel和TableLayoutPanel)不兼容。
  • 不支持直接以與.NET 兼容框架所需的顯示分辨率進行縮放。

所以,雖然該機制在.NET 2.0中保留以維護向后兼容性,但它已經被下面將要介紹的更可靠的機制所取代。因此,預期相關的類AutoScale, ApplyAutoScaling, AutoScaleBaseSize和某些Scale重載已過時。

現在對自動縮放的支持

在.NET 2.0中對Windows窗體的縮放的改進如下:

  • 對ContainerControl類的縮放提供了支持,這樣forms, native composite控件以及自動以控件獲得了同一的縮放支持。添加了AutoScaleFactor, AutoScaleDimensions, AutoScaleMode和PerformAutoScale類。
  • Control類添加了若干新成員,這些新成員用於輔助該類參與縮放並支持在同一窗體上進行混合縮放。具體地說,Scale, ScaleChildren, GetScaledBounds成員用於支持縮放。
  • 添加了建立在愛屏幕分辨率基礎上的縮放支持,如AusoScaleMode枚舉類所定義的。該模式與.NET Compact Framework的自動縮放兼容,從而更易於進行應用程序的遷移。
  • 自動縮放與FlowLayoutPanel和TableLayoutPanel等布局管理器兼容。
  • 縮放因子現在以浮點值表示,通常為SizeF類型,所以消除了舍入誤差。

注意:還不支持DPI和字體混合模式縮放。雖然可以使用一種模式(如DPI)縮放某個控件,然后使用另一個模式(字體)將該控件放置在窗體上,這樣做沒有問題,但是某個模式下的基窗體和另一個模式下的派生窗體混合時,會導致不可預料的結果。

自動縮放實現

Windows窗體現在使用下面的邏輯實現自動縮放:

  1. 設計時,每個ContainerControl分別在AutoScaleMode和AutoScaleDimensions中記錄縮放模式和當前分辨率
  2. 運行時,實際分辨率存儲在CurrentAutoScaleDimensions屬性中。AutoScaleFactor屬性會動態計算運行時分辨率和設計時分辨率的比值。
  3. 加載窗體時,如果CurrentAutoScaleDimensions和AutoScaleDimensions的值不同,則會調用PerformAutoScale方法對該空間及其子控件進行縮放。該方法會掛起布局並調用Scale方法執行實際的縮放。之后,更新AutoScaleDimensions以避免累計縮放。
  4. 在下面的情況也會調用PerformAutoScale:
    • 如果縮放模式為Font,響應OnFontChanged事件。
    • 繼續執行容器控件布局時檢測到AutoScaleDimensions或AutoScaleMode屬性發生改變。
    • 檢測到父ContainerControl在被縮放。每個容器控件只負責使用自己的比例縮放自己的子控件,對父容器中的控件不負責。
  5. 子控件可通過以下的方式修改其縮放行為:
    • 重寫ScaleChildren屬性以確定其子控件是否應縮放。
    • 重寫GetScaledBounds方法以調整控件縮放的邊界,但不調整縮放邏輯。
    • 重寫ScaleControl方法更改當前控件的縮放邏輯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM