[转载]Pyside 开发 DPI 自适应窗口程序技巧

现在都是超清屏的时代了。PC虽然没有手持设备需要考虑尺寸的问题,但是由于这些超清屏的出现,导致不同电脑上的DPI设置大不相同。而此时如果程序开发如果还偷懒使用像素对齐的话,在高DPI设备上就会出现扭曲变形的问题。
 
最近我一直在用 PySide 在 Python 下做 GUI 界面开发。今天忽然想到 DPI 缩放的问题,于是做了些尝试。网上似乎现在也没有比较好的教程(中英文我都没搜到),所以我把心得写在这里,希望对同样遇到这个问题的人有用。
 
一、利用 layout 来组织控件
 
为了使窗口在不同DPI下不变形,而且能够在高DPI下自适应的关键是两点: 利用 layout 来组织窗口,使空间能随着窗口尺寸和显示内容自动调整大小;以及,根据DPI自动调整窗口的大小。
 
layout 是 Qt 一个非常强大的功能,主要用来对齐和排列窗口,个人推荐无论在做任何程序开发都是用 layout 来对控件进行排列,而不是使用像素对齐。其在 Qt Designer 中 layout 控件看起来是这样的:

[转载]Pyside <wbr>开发 <wbr>DPI <wbr>自适应窗口程序技巧
 
具体使用方式自己去感受下。这里有个很好的教程(需翻墙): http://www.youtube.com/watch?v=2edb0VOkx-k
 
我的窗口排完了后是这样的:
 
[转载]Pyside <wbr>开发 <wbr>DPI <wbr>自适应窗口程序技巧
 
运行一下就可以发现无论如何调整窗口大小,控件都会自适应。而且就算里面文字随DPI大小缩放后,空间依然能保持整齐。
 
二、根据系统DPI自动调整
 
为了保持窗口大小的一致性,另外需要做的就是针对系统DPI大小进行窗口调整。
 
Windows 下高分辨显示器的放大功能,主要是通过调整系统DPI实现的。比如默认的100%大小的系统界面是96 DPI (奇怪我记得早些年我的印象是75,可能是我记茬了)。而放大到125% 则是将 DPI x 125 %,即将系统DPI设定到120 DPI。
 
要保持窗口在不同 DPI 下有一致的外观,其实就是简单将窗口尺寸放大和 Windows 一样的倍数。比如下120 DPI 下将窗口放大1.25倍,由于控件是使用 layout 对齐的,因此其位置也会进行相应调整。
 
放大的倍数 = 当前系统DPI / 默认DPI(96)。Windows API 中还发现,其实 DPI 可以在 X 轴和 Y 轴实现不同比例缩放。所以程序的长和宽最好分开针对 X 和 Y 轴的DPI缩放比例进行设置。
 
上面的操作需要对 Windows API 进行访问,在 Python 下需要安装一个第三方的库 PyWin32,下载地址如下:
 
 
通过调用 win32print.GetDeviceCaps 函数可以获得系统在 X 和 Y 轴的当前DPI值(查找这个函数简直用掉了我一生的时间!)。我写了两个函数,代码如下,通过这两个函数可以返回系统的 DPI 以及所需要的放大倍数。
 
#!/usr/bin/env python2.7
 
 
"""
Contains some functions related to windows api.
 
Linzhou (linzhou.zhang.china@gmail.com)
"
""
 
import win32gui
import win32print
 
def get_win_dpi():
 
    """ this function get the dpi on X and Y axis of default windows desktop.
 
    In:
    none
 
    Out:
    x_dpi: dpi on x axis. [int]
    y_dpi: dpi on y axis. [int]
 
    "
""
 
    para_x = 88     # magic number of windows API for x axis
    para_y = 90     # magic number of windows API for y axis
 
    hdc = win32gui.GetDC(0)
    x_dpi = win32print.GetDeviceCaps(hdc, para_x)
    y_dpi = win32print.GetDeviceCaps(hdc, para_y)
    return x_dpi, y_dpi
 
#enddef get_windows_dpi
 
 
def get_program_scale_factor():
 
    """ This function calculate the scale factor based on the current DPI setting.
 
    In:
    none
 
    Out:
    scale_x: scale factor on x axis. [float]
    scale_y: scale factor on y axis. [float]
 
    "
""
 
    default_dpi_x = 96.0        # default x axis dpi setting for windows
    default_dpi_y = 96.0        # default y axis dpi setting for windows
 
    current_dpi_x, current_dpi_y = get_win_dpi()
    current_dpi_x = float(current_dpi_x)
    current_dpi_y = float(current_dpi_y)
 
    scale_x = current_dpi_x / default_dpi_x
    scale_y = current_dpi_y / default_dpi_y
 
    return scale_x, scale_y
 
#enddef get_window_scale_factor
 
 
if __name__ == '__main__':
    #Test
 
    scale_x, scale_y = get_program_scale_factor()
    print scale_x
    print scale_y
 
scale_x 和 scale_y 就是需要放大的倍数,如果系统当前DPI是96的话,那么它们就是1。
 
在代码中将窗口大小乘以这个系数,窗口就自动对DPI实现大小调整了。示例如下:
 
    #generate window
    app=QtGui.QApplication(sys.argv)
    Window=NewMainWindow()
    # Get scale factor and resize
    scale_x, scale_y = get_program_scale_factor()
    init_size_x, init_size_y = 820, 505
    Window.resize(init_size_x * scale_x, init_size_y * scale_y)
    Window.show()
 
Done!就是这么简单。
 
三、示例:
 
下面是我自己的一个程序在 Windows 8.0 下 100%、120% 和150% DPI 状态下运行情况,可以看到基本是等比例放大,而且没有任何因为DPI调整而变形的情况。

[转载]Pyside <wbr>开发 <wbr>DPI <wbr>自适应窗口程序技巧
100 %
 
[转载]Pyside <wbr>开发 <wbr>DPI <wbr>自适应窗口程序技巧
120%
 
[转载]Pyside <wbr>开发 <wbr>DPI <wbr>自适应窗口程序技巧
150%
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值