APP下载

高分屏下的软件大小的自适应调整

2018-02-28涂焱楚

电子技术与软件工程 2018年21期

涂焱楚

摘要

高分屏带来的一系列问题,包括字体模糊等,其全面的解决有待于操作系统的完善和软件开发技术的提高;但是如果我们在编程中,能针对屏幕的大小,对软件窗口大小做自适应调整,和在绘图输出选择适当的坐标映射模式,可以适当地减轻这个问题的影响。

【关键词】高分屏下 软件大小 自适应调整

1 引言

随着PC显示设备性能的提升,大批PC开始采用高分屏,主流的笔记本电脑基本都能达到1920*1080的高清分辨率;这样高的分辨率,好处是画面更为细腻清晰,尤其是在播放高清视频时,效果会更为逼真;但也带来了一些问题,特别是在笔记本和平板电脑上,较高的分辨率,使得原来在普通屏幕下开发的软件运行起来,原来的窗口、文字、图标都显得非常小,看起来很不舒服,特别是视力不好的人,看起来更不方便。即使把窗口放大或是最大化,但是也有很多造成窗口中的输出的内容比例失调,不能同步跟随变化。这种问题在笔记本电脑尤为明显,毕竟为了便于携带,笔记本电脑的显示屏幕一般为15寸或14寸,不可能像台式机一样,大幅度增大显示屏幕,但在这样高分辨率情况下,自然是一个像素点会显得比较小。另一方面,在高分屏上开发的软件,如果不注意,一旦要在普分屏上运行,又会显得软件的窗体太大,不协调。

2 针对屏幕大小,调整软件本身窗口的大小

在Windows系统下,开发一个桌面应用的时候,窗口的大小的设置一般采用像素为单位。采用像素为单位的问题是不同分辨率、不同大小的物理输出屏幕下,显示的大小不一,不能根据输出屏幕的大小做调整。在这方面,我们有两种选择,第一种,我们可以取得屏幕的物理大小,也知道屏幕的分辨率,从而确定单位大小的像素个数,我们就可以用绝对的单位,来规定软件窗口的大小,例如长宽是多少毫米,或是多少英寸,然后实际设置时再转换成像素的个数。在这种情况下,不管是什么物理大小屏幕,我们可以保证窗口的大小是一致的。第二种情况,如果我们无法确定输出屏幕的绝对物理大小,那么我们也可以根据屏幕的分辨率,取一个相对比例,例如在1920*1080的分辨率,我们取分辨率的2/3,也就是1280*720像素大小,在这种情况下,我们一般也能保证不管屏幕的物理大小是14寸或是15寸,也可以保证软件窗口的初始大小是适中的,不会因高分屏而显得过小,而在普分屏的情况下,屏幕分辨率的2/3也是一个适中的数字,保证我们软件窗体的大小是看起来舒适的,不会显得过大或过小。

要实现这些功能,刚好在windows SDK中有一个API,GetDeviceCaps(HDC hDC,intindex),顾名思义,这个API可以了解设备的能力,也就是设备的一些功能参数。其中入口参数的hDC,是设备上下文(DeviceContext)的句柄,index是一个常量值索引,其中常见的命名符号常量值有:HORZSIZE、VERTSIZE、HORZRES、VERTRES、LOGPIXELSX、LOGPIXELSY等。其中采用HORZSIZE、VERTSIZE为索引可以取得物理屏幕的宽度和高度,以毫米为单位;以HORZRES、VERTRES为索引则可以取得屏幕的分辨率,以像素点为单位。

例如,我们如果想取得输出屏幕的物理大小,可以这样来调用:

HDC hdcScreen=::GetDC(NULL);//取得屏幕的设备上下文句柄

int xMM=GetDeviccCaps(hdcScreen,HORZSIZE);

int yMM=GetDeviceCaps(hdcScreen,VERTSIZE);

现在xMM中就是以毫米为单位的显示屏幕的宽度,yMM中就是以毫米为单位的显示屏幕的高度;有了這两个数值,再用参数索引HORZRES和VERTRES来调用GctDeviceCaps可以取得屏幕的分辨率,也就可以算出单位毫米的像素多少,间接用毫米为单位确定窗体大小。

但是,这样得到的屏幕的大小并不是特别精确,存在一定的偏差;在windows7系统下,其偏差还比较大。这样的话,我们可以直接采用第二种方案,采屏幕分辨率的2/3作为窗口的大小。

在VC环境下,我们可以重载窗口类的PreCreateWindow(CR-EATESTRUCT&cs)方法,修改cs中的cx和cy值,也就是窗口的宽和高,它们都是以像素为单位的。这样,就可以在一定程度上保证,我们软件窗口的初始大小不会过大或过小。

代码如下:

HDC hdcScreen=::GetDC(NULL);

int xpx=GetDeviceCaps(hdcScreen,HORZRES);

int yPx=GetDeviceCaps(hdcScreen,VERTRES);

cs.cx=xPx*2/3;

cs.cy=yPx*2/3;

3 选择适当的坐标映射模式进行绘图输出

我们在确定了软件的主窗口的大小后,在窗口客户区绘制输出,为了方便灵活,同样可以不采用直观的像素单位,而以更接近实际的单位来进行输出;这样,我们就需要调整坐标映射模式。

在Windows应用程序的开发中,文本、图形的绘制函数采用的是一种逻辑坐标系统,而实际的设备输出采用的是设备坐标系统。设备坐标以像素为单位,原点固定在窗口的左上角,向右的方向为x轴正方向,向下的方向为y轴正方向。将逻辑坐标转换成设备坐标,是通过设置所谓的坐标映射模式来完成的。在windows系统中一共有八种坐标映射模式,可以通过CDC类中SetMapMode(int nMapMode)方法来设置,其中nMapMode参数是一个整型值,不同的取值代表不同模式,可以取以下的常量值:

(1)MM_ANISOTROPIC。自定义的映射模式,这种映射模式在x方向和y方向均使用自定义的单位长度,并且两个方向上的单位长度可以不一样。

(2)MM_ISOTROPIC。自定义的映射模式,这种映射模式在x方向和y方向上使用相同的单位长度。

(3)MM_HHENGLISH。以0.001英寸为逻辑单位长度,向右的方向为x轴正方向,向上的方向为y轴正方向。

(4)MM_HIMETRIC。以0.01毫米为逻辑单位长度,向右的方向为x轴正方向,向上的方向为y轴正方向。

(5)MM_LOENGLISH。以0.01英寸为逻辑单位长度,向右的方向为x轴正方向,向上的方向为y轴正方向。

(6)MM_LOMETRIC。以0.1毫米为逻辑单位长度,向右的方向为x轴正方向,向上的方向为y轴正方向。

(7)MM_TEXT。以1设备像素为逻辑单位长度,向右的方向为x轴正方向,向下的方向为y轴正方向。在本坐标模式下,逻辑单位和设备单位是一致的。

(8)MM_TWIPS。以1/20磅为逻辑单位长度,向右的方向为x正方向,向上的方向为y轴正方向。

这其中的MM_TExT坐标映射模式是最直观,最易于使用的一种坐标映射模式,也是缺省的坐标映射模式。在这样的坐标系统中,向右的方向为x轴的正方向,向下的方向为y轴的正方向。无论是x方向还是y方向,每一个单位长度都代表设备上的一个像素。这样输出函数的所用的逻辑坐标和实际输出的设备坐标是相同的。这种映射模式在实际中也得到了较多的应用,它又是缺省的映射模式,以至于很多人编程中都忘记了坐标模式的映射这回事。当然,它的问题也是很明显的。不同的设备,同一个像素点的大小是不相同的。同样一个14寸的笔记本电脑,在1366*768的分辨率下,150*150。大小的一个矩形,还可以轻松的分辨。但是在1920*1080的分辨率下,就未免显得太小了,让人看起来不舒服。

其他的几种模式,是一种设备无关的映射模式。Windows绘图输出函数中使用的x值和y值这些坐标是一种逻辑单位,它们表示的单位距离可以由用户设定;而实际的输出设备采用的x值和y值表示的单位距离是实际显示设备上的像素点。其中,MM_LOMETRIC、MM_LOENGLISH等映射模式以0.1毫米、0.01英寸之类的绝对长度为单位,当在不同的设备上输出的时候,对应的像素点个数是不相同的,将逻辑单位换算成设备单位由系统来自动完成。

因此如果采用MM_LOMETRIC模式,由于它的单位是0.1mm,所以在150*150大小的矩形实际上是1.5cm*1.5cm,至于在不同设备对应到多少个像素,这个由windows系统帮我们来进行转换,系统保证在不同的输出设备下,它都统一是1.5cm的一个矩形。下面的代码采用MM_LOMETRIC映射模式在屏幕上输出10毫米*10毫米的一个矩形。

CReet rt;

GetClientRect(rt);

pDC->SetViewPortorg(0,rt.Height());//設置逻辑坐标的原点在设备坐标上的位置是左下角

pDC->SetMaPMode(MM_LOMETRIC);//设置坐标映射模式

pDC->Rectangle(CRect(0,0,100,100));

另外,我们也可以采用MM_ANISOTROPIC映射模式或MM_ISOTROPIC坐标模式,这两种模式可以自定义逻辑坐标和设备坐标的映射关系。其中MMA卜ISOTROPIC模式可以建立长和宽的逻辑坐标与设备坐标不同的映射关系,实现对绘制函数绘制的图形在纵横比上进行任意的缩放。MM_IsoTRoPIe坐标模式与MM_ANISOTROPIC坐标模式不同,该坐标模式也可以建立逻辑坐标与设备坐标不同的映射关系,实现对绘制函数绘制的图形进行比例缩放,但不会改变图形的纵横比。

MM_ANISOTROPIC和MM_ISOTROPIC这两种映射模式需要设置逻辑单位和设备单位间的对应(比例)关系,设置方法是定义两个矩形,第一个矩形以逻辑单位表示进行绘制的范围大小,第二个矩形以设备单位(即像素)表示第一个矩形范围代表的设备范围大小,这样就确定了逻辑单位和设备单位间的转换关系。在Windows系统中,第一个矩形一般称为窗口,而第二个矩形则称为视口。设置窗口和视口位置及范围的CDC成员如下:

SetViewportOrg((POINT point)//设置窗口坐标的原点在设备坐标上的位置

SetWindowExt(SIZE size)//设置窗口的大小

SetViewportExt(SIZE size)//设置视口的大小

实际应用中,由于MM_ANISOTROPIC坐标模式可以改变逻辑坐标与设备坐标间的比例关系,所以在应用程序中可以先为窗口假定一个长、宽尺寸即设定逻辑尺寸,然后根据该尺寸绘制好图形。当窗口尺寸被改变即窗口物理尺寸发生变化时,只要改变逻辑坐标与设备坐标间的比例关系,就可以使得窗口的逻辑尺寸依然不变,使得采用逻辑坐标绘制的图形在窗口内的相对位置不变。

下面的代码即采用MM_ANISOTROPIC映射坐标模式输出一个长宽为100个逻辑单位的矩形。

CRect elientRect;

GetClientReet(clientReet);

pDC->SetMaPMode(MM_ANISOTROPIC);

pDC->SetViewportOrg(0,0);//设置窗口坐标的原点在设备坐标上的左上角

pDC->SetWindowExt(500,500);//设置窗口的范围

pDC->SetViewportExt(clientRect.right,clientRect.bottom);//对应窗口范围的实际设备输出范围

pDC->Rectangle(CRect(0,0,100,100));

4 结论

综上所述,我们在编程时,设置窗口的大小和图形、文本的绘制输出时,不是单纯的方便省事,采用像素为单位,而是根据输出屏幕的大小,采用更为自然和实际的输出坐标单位,将更能让输出的结果适应于不同大小和分辨率的屏幕,让最终显示效果更为自然、协调和一致。