zoukankan      html  css  js  c++  java
  • 关于Windows高DPI的一些简单总结(Window上一般默认是96 dpi 作为100% 的缩放比率)

    我们知道,关于高DPI的支持, Windows XP时代就开始有了, 那时关于高DPI的支持比较简单, 但是从Vista/Win7 到现在Win8 /Win8.1, Windows关于高DPI的支持已经发生了很大的变化, 下面我们依次简单介绍下。
     
    如果说以前XP时代我们还有理由不关注高DPI,  那么在移动设备时代和大显示器的高分辨率时代, 我们就没有理由不关注高DPI了, 比如Surface Pro的分辨率是1920x1080, 这种情况下如果系统我们不设置高DPI, 基本上就没法触摸和操作了,所以现在普通程序对高DPI的支持已经成为趋势了。 
     
    什么DPI? 全称是dots per inch (DPI), 也就是每英寸的点数,在显示器上就是每英寸的像素个数,Window上一般默认是96 dpi 作为100% 的缩放比率, 但是要注意的是该值未必是真正的显示器物理值, 只是Windows里我们的一个参考标准。
     
    下面我们思考为什么DPI设置高了之后, 我们看到的字体会变大? 因为系统字体是是以固定大小(宋体10号字,物理尺寸为(10/72)英寸)设计的, 当我们DPI设置高了之后 ,说明该字体要占有更多的像素, 在屏幕分辨率不变的前提下, 看起来也就大了。所以如果我们设置高DPI,通常也意味着我们的显示器是高分辨率, 里面的字体看起来太小了, 我们需要提高DPI来把内容放大。
     
    那么我们的程序如何才能支持高DPI? 对于高DPI的支持, 不同操作系统有不同的方案。通常来说如果我们程序支持高DPI, 意味着我们要对绘画的内容进行相应的放大, 比如字体,图片和控件等。当然, 如果我们用的是系统字体(比如GetStockObject(DEFAULT_GUI_FONT)), 那么这种情况下我们不用操心, 因为系统会对该字体在高DPI时进行相应的放大; 如果我们是用CreateFont自己创建的字体, 那就要我们自己对该字体进行放大了。
     
    下面我们看XP是如何对高DPI进行支持的? 
     
    XP对高DPI的支持比较差劲, 大部分情况下就是字体的放大, 当然我们程序也可以通过GetDeviceCaps(hDC, LOGPIXELSX)获取DPI后自己对绘画的内容进行缩放。
     
     
    下面我们看Vista/Win7/Win8是如何对高DPI进行支持的?
     
    我们知道Vista/Win7我们可以禁止DWM(Desktop Window Manager), 该模式我们称之为Basic模式, 这种模式下的高DPI效果和XP一样。
     
    对于DWM没有禁掉的情况, Vista/Win7/Win8 对高DPI的支持又分为2种情况, 具体看下图: 
     
    一种XP风格的高DPi支持, 这种方式我们上面讨论过了;
    还有一种是通过 DWM 虚拟化支持的 高DPI方式, 下面我们讨论下该方式: 
     
    该种方式的高DPI支持是通过DWM的缩放实现的, 具体过程是这样的, 比如我们当前系统的DPI是200%, 我们程序运行时,系统会告诉你当前DPI仍然是96(100%), 所以我们程序会仍然按照100%的方式进行绘画, 但是但是系统给我们的坐标是根据DPI缩小过后的(也就是我们对窗口调用GetWindowRect或是通过GetSystemMetrics(SM_CXSCREEN)得到的大小会比实际大小减半) , 当我们画完之后, DWM再对整个窗口进行200% 放大后画到屏幕上, 这样看起来我们的程序就自动支持高DPI了。
     
     这种方式看起来很美妙, 但是它也有缺点, 主要是经过缩放后的内容看起来会变模糊, 比如文字会有明显的锯齿。
     
    既然DWM虚拟化用户效果有时不是那么好, 那么我们很多时候可能会自己支持高DPI, 如何让我们的程序禁用该效果?
    事实上我们可以对每个进程对DWM虚拟化的支持进行设置和查询, 系统给我们提供了2个APi: SetProcessDPIAware 和 IsProcessDPIAware , 通过调用SetProcessDPIAware , 我们告诉系统不要对我们的程序进行DWM虚拟化。
     
    这里还有特殊情况也提一下: 我们在高DPI下通过窗口句柄取到的坐标信息是和目标程序是否支持DWM虚拟化相关联的, 我们对其他支持DWM虚拟化的程序窗口调用GetWindowRect, 取到的坐标也是经过DWM缩放后的坐标; 对禁用DWM虚拟化程序的窗口调用GetWindowRect, 取到的坐标则是没有经过缩放的原始坐标。
     
     最后我们再讨论下Win8.1 对高DPI的支持, WIn8.1对高DPi以3种方式支持 Process_DPI_Awareness : 
     
    typedef enum _Process_DPI_Awareness { 
      Process_DPI_Unaware            = 0,
      Process_System_DPI_Aware       = 1,
      Process_Per_Monitor_DPI_Aware  = 2
    } Process_DPI_Awareness;
     
    下面我们依次讨论这3种方式: 
     
    第一种Unaware, 该种方式是告诉系统, 我的程序不支持DPI aware, 请通过DWM虚拟化帮我们实现。 该方式和上面Win7/Win8对高DPI的支持的实现基本一样,主要区别是它通过GetWindowRect取到的坐标都是经过DWM缩放后的, 无论对方窗口是不是支持DWM虚拟化。
     
    第二种方式是System DPI aware, 该方式下告诉系统, 我的程序会在启动的显示器上自己支持DPI aware, 所以不需要对我进行DWM 虚拟化。 但是当我的程序被拖动到其他DPI不一样的显示器时, 请对我们先进行system DWM虚拟化缩放。
     
    第三种方式是Per Monitor DPI aware, 该方式是告诉系统, 请永远不要对我进行DWM虚拟化,我会自己针对不同的Monitor的DPi缩放比率进行缩放。
     
    再介绍下相关API:
    SetProcessDpiAwareness :设置当前进程对高DPi的支持方式
    GetProcessDpiAwareness :查询某个进程对高DPI的支持方式
    GetDpiForMonitor : 获取某个Monitor的DPI
    WM_DPICHANGED :当某个程序窗口被拖到另外一个DPI的Monitor时收到
     
    最后,简单总结下, 从上面我们可以看到微软在不同操作系统上对高DPI支持的改进线路,很多方面也体现了他们对老程序兼容性上的考虑, DWM虚拟化虽然很简单, 却丢失了用户体验。  
     
    PS, 我在我机器上测试发现,桌面程序基本上只有微软自己的程序能做到在高DPI下完美支持, 其他大部分程序(即使如Chrome)也是通过DWM虚拟化实现的高DPI支持。当然现在WPF和Window store App基本上都是内置支持高DPI的。
     
    统计下, 你们的程序支持高DPI吗? 
     
                      High DPI Settings in Windows

    http://www.cnblogs.com/weiym/p/3555068.html

  • 相关阅读:
    hdu 5224 Tom and paper 水题
    2015 UESTC 搜索专题N题 韩爷的梦 hash
    2015 UESTC 搜索专题M题 Palindromic String 马拉车算法
    2015 UESTC 搜索专题K题 秋实大哥の恋爱物语 kmp
    2015 UESTC 搜索专题J题 全都是秋实大哥 kmp
    2015 UESTC 搜索专题F题 Eight Puzzle 爆搜
    2015 UESTC 搜索专题E题 吴队长征婚 爆搜
    2015 UESTC 搜索专题D题 基爷的中位数 二分
    2015 UESTC 搜索专题C题 基爷与加法等式 爆搜DFS
    2015 UESTC 搜索专题B题 邱老师降临小行星 记忆化搜索
  • 原文地址:https://www.cnblogs.com/findumars/p/5785904.html
Copyright © 2011-2022 走看看