[转载]Pyside 开发 DPI 自适应窗口程序技巧
原文地址:Pyside 开发 DPI 自适应窗口程序技巧作者:风叔
现在都是超清屏的时代了。PC虽然没有手持设备需要考虑尺寸的问题,但是由于这些超清屏的出现,导致不同电脑上的DPI设置大不相同。而此时如果程序开发如果还偷懒使用像素对齐的话,在高DPI设备上就会出现扭曲变形的问题。
最近我一直在用 PySide 在 Python 下做 GUI 界面开发。今天忽然想到 DPI
缩放的问题,于是做了些尝试。网上似乎现在也没有比较好的教程(中英文我都没搜到),所以我把心得写在这里,希望对同样遇到这个问题的人有用。
一、利用 layout 来组织控件
为了使窗口在不同DPI下不变形,而且能够在高DPI下自适应的关键是两点: 利用 layout
来组织窗口,使空间能随着窗口尺寸和显示内容自动调整大小;以及,根据DPI自动调整窗口的大小。
layout 是 Qt 一个非常强大的功能,主要用来对齐和排列窗口,个人推荐无论在做任何程序开发都是用 layout
来对控件进行排列,而不是使用像素对齐。其在 Qt Designer 中 layout 控件看起来是这样的:
具体使用方式自己去感受下。这里有个很好的教程(需翻墙):http://www.youtube.com/watch?v=2edb0VOkx-k
我的窗口排完了后是这样的:
运行一下就可以发现无论如何调整窗口大小,控件都会自适应。而且就算里面文字随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 ([email protected])
"""
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调整而变形的情况。
120%
150%