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

自动缩放的必要性

如果没有自动缩放功能,当改变显示分辨率或字体时,其对应的应用不是显得太大,就是显得太小。例如,为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. 通过WebViewJavascriptBridge实现OC与JS交互

      在.m方法当中,申明一个WebViewJavascriptBridge属性: @interface ExampleAppViewController () @property WebViewJav ...

  2. hdu 1036 (I/O routines, fgets, sscanf, %02d, rounding, atoi, strtol) 分类: hdoj 2015-06-16 19:37 32人阅读 评论(0) 收藏

    thanks to http://stackoverflow.com/questions/2144459/using-scanf-to-accept-user-input and http://sta ...

  3. 将excel2003文档文件转换为excel2007格式

    在sharepoint 2010 中,excel2007或excel 2010文档格式,支持web app 应用,能够在浏览器在线打开,查看,但excel 2003格式的文档只能用office客户端打 ...

  4. rails常用验证方法 (转)

    validates_presence_of       :login,  :message => "用户名不能为空!" validates_length_of         ...

  5. php 无法连接mysql

    sql_connect,sqli_connect, 或new sqli() 无法建立mysql连接 1. php.ini 中 ; extension=php_mysql.dll 和 ; extensi ...

  6. 解决ASP.NET 自定义报表部署到IIS浏览时出现ASP.NET会话已结束问题

    进到公司开始接触的项目就要做报表,原系统使用的是水晶报表,但是水晶报表展示方面美观方面不怎么好需客户需要美化一下.自定义报表与水晶报表之前都没有接触过,自己先学了一下这两种报表,后面觉得自定义报表设计 ...

  7. java 后台校验格式

    package com.hengxin.qianee.utils; import java.net.InetAddress; public class RegexUtils { /** * 用户名是否 ...

  8. android 镜像源

    Android SDK在线更新镜像服务器 中国科学院开源协会镜像站地址: IPV4/IPV6: mirrors.opencas.cn 端口:80 IPV4/IPV6: mirrors.opencas. ...

  9. HDU 1548 A strange lift (bfs / 最短路)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1548 A strange lift Time Limit: 2000/1000 MS (Java/Ot ...

  10. linux常见目录的作用

    根目录下的bin 和sbin,usr目录下的bin和sbin四个都是保存系统命令.bin下的普通用户都可以使用,sbin下只有超级用户root可以使用 pro和syc不能直接操作,是内存的过载点 / ...