通过自动缩放功能,能使在一个计算机上设计的界面在另一个具有不同分辨率或系统字体的计算机上能正常显示。这样窗体及其控件就能通过智能化调整大小以保障在本地电脑和用户电脑上保持一致。

自动缩放的必要性

如果没有自动缩放功能,当改变显示分辨率或字体时,其对应的应用不是显得太大,就是显得太小。例如,为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。该方法先计算AutoScaleBaseSize和Font的相对大小,然后调用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方法更改当前控件的缩放逻辑。

Windows窗口自动缩放机制的更多相关文章

  1. (译)Windows Azure的7月更新:SQL数据库,流量管理,自动缩放,虚拟机

    Windows Azure的7月更新:SQL数据库,流量管理,自动缩放,虚拟机 今早我们释出一些很棒的Windows Azure更新.这些新的提升包括:SQL数据库:支持SQL自动导出和一个新的高级层 ...

  2. C#自动切换Windows窗口程序,如何才能调出主窗口?

      namespace AutoChangeWindow { partial class Form1 { /// <summary> /// 必需的设计器变量. /// </summ ...

  3. Windows内核读书笔记——Windows异常分发处理机制

    本篇读书笔记主要参考自<深入解析Windows操作系统>和<软件调试>这两本书. IDT是处理异常,实现操作系统与CPU的交互的关口. 系统在初始化阶段会去填写这个结构. ID ...

  4. 【转】Windows 窗口层次关系

    原文链接:undefined! 相信在Windows 下面编程的很多兄弟们都不是很清楚Windows 中窗口的层次关系是怎么样的,这个东西很久已经研究过一下,后来又忘记了,今天又一次遇到了这个问题,所 ...

  5. Windows程序内部运行机制 转自http://www.cnblogs.com/zhili/p/WinMain.html

    一.引言 要想熟练掌握Windows应用程序的开发,首先需要理解Windows平台下程序运行的内部机制,然而在.NET平台下,创建一个Windows桌面程序,只需要简单地选择Windows窗体应用程序 ...

  6. 关于Windows窗口框架

    我们知道Windows的窗口消息处理函数是C方式, 面向过程的, 所以窗口框架的基本任务就是将它转成面向对象的方式, 确切的说如何将消息处理函数第一参数HWND转成对象指针. 关于这个问题, 其实网上 ...

  7. 深入浅出话VC++(1)——Windows程序内部运行机制

    一.引言 要想熟练掌握Windows应用程序的开发,首先需要理解Windows平台下程序运行的内部机制,然而在.NET平台下,创建一个Windows桌面程序,只需要简单地选择Windows窗体应用程序 ...

  8. VC菜菜鸟:建立第一个基于Visual C++的Windows窗口程序

    建立第一个基于VisualC++的Windows窗口程序: 发表于:http://blog.csdn.net/it1988888/article/details/10306585 a)执行命令:新建 ...

  9. Windows窗口消息大全(转)

    Windows窗口消息大全,全不全自己看 ////////////////////////////////////////////////////////////////////////// #inc ...

随机推荐

  1. 在 Vultr VPS 中 以 Debian 8 i386 (jessie) 为 操作系统 平台 手动 搭建 PPTP VPN 全过程

    更新服务器并安装 PPTP 服务  apt-get update apt-get upgrade apt-get install pptpd 编辑 /etc/pptpd.conf 找到 #locali ...

  2. 初学JavaScript七大注意事项

    知识说明: 初学JavaScript,注意以下七大细节,在实现同样功能的情况下,让我们的代码更易懂.效率更高. 一.简化代码 例如:创建对象 之前是这样的: Var car = new object( ...

  3. GFT_News Auto

    using AnfleCrawler.Common; using Newtonsoft.Json.Linq; using System; using System.Collections.Generi ...

  4. MapReducer程序调试技巧

    写过程序分布式代码的人都知道,分布式的程序是比较难以调试的,但是也不是不可以调试,对于Hadoop分布式集群来说,在其上面运行的是mapreduce程序,因此,有时候写好了mapreduce程序之后, ...

  5. [UIImage resizableImageWithCapInsets:]

    [UIImage resizableImageWithCapInsets:]使用注意 转自:http://www.cnblogs.com/scorpiozj/p/3302270.html 最近在sae ...

  6. ie 11 cookie 的值为空

    昨天碰到ie 11上运行的程序时  登录老是登录不上去 一直是登录界面 最后检查半天发现时因为 权限验证登录时 获取cookie里的用户信息时 一直为空 便在网上查询资料  发现是因为ie11 里貌似 ...

  7. hdu 2059

    ps:终于解决了....卡了我好久.最后用了DP.然后还有记忆化搜索优化了一下.终于AC了 思路:要计算dp[n](就是到第n个站的最短时间,也就是最优方案),必须知道dp[0]到dp[n-1] 设j ...

  8. Java程序员应更新的知识

    2013: 你应该更新的Java知识之常用程序库(一) 你应该更新的Java知识之常用程序库(二) 你应该更新的Java知识之Observer 你应该更新的Java知识之集合初始化 你应该更新的Jav ...

  9. swiper的使用

    最近要用html5制作可以一屏一屏向上滑动的页面,发现大家使用swiper插件的较多,所以试了试,发现做出来的效果还不错,喜欢的朋友可以参考一下自己动手做啦. 1.首先我们要引入4个文件: <h ...

  10. C# 获取MAC地址

    /********************************************************************** * C# 获取MAC地址 * 说明: * 在C#中获取本 ...