涂焱楚
摘要
高分屏帶來的一系列問題,包括字體模糊等,其全面的解決有待于操作系統(tǒng)的完善和軟件開發(fā)技術(shù)的提高;但是如果我們在編程中,能針對屏幕的大小,對軟件窗口大小做自適應(yīng)調(diào)整,和在繪圖輸出選擇適當(dāng)?shù)淖鴺?biāo)映射模式,可以適當(dāng)?shù)販p輕這個(gè)問題的影響。
【關(guān)鍵詞】高分屏下 軟件大小 自適應(yīng)調(diào)整
1 引言
隨著PC顯示設(shè)備性能的提升,大批PC開始采用高分屏,主流的筆記本電腦基本都能達(dá)到1920*1080的高清分辨率;這樣高的分辨率,好處是畫面更為細(xì)膩清晰,尤其是在播放高清視頻時(shí),效果會更為逼真;但也帶來了一些問題,特別是在筆記本和平板電腦上,較高的分辨率,使得原來在普通屏幕下開發(fā)的軟件運(yùn)行起來,原來的窗口、文字、圖標(biāo)都顯得非常小,看起來很不舒服,特別是視力不好的人,看起來更不方便。即使把窗口放大或是最大化,但是也有很多造成窗口中的輸出的內(nèi)容比例失調(diào),不能同步跟隨變化。這種問題在筆記本電腦尤為明顯,畢竟為了便于攜帶,筆記本電腦的顯示屏幕一般為15寸或14寸,不可能像臺式機(jī)一樣,大幅度增大顯示屏幕,但在這樣高分辨率情況下,自然是一個(gè)像素點(diǎn)會顯得比較小。另一方面,在高分屏上開發(fā)的軟件,如果不注意,一旦要在普分屏上運(yùn)行,又會顯得軟件的窗體太大,不協(xié)調(diào)。
2 針對屏幕大小,調(diào)整軟件本身窗口的大小
在Windows系統(tǒng)下,開發(fā)一個(gè)桌面應(yīng)用的時(shí)候,窗口的大小的設(shè)置一般采用像素為單位。采用像素為單位的問題是不同分辨率、不同大小的物理輸出屏幕下,顯示的大小不一,不能根據(jù)輸出屏幕的大小做調(diào)整。在這方面,我們有兩種選擇,第一種,我們可以取得屏幕的物理大小,也知道屏幕的分辨率,從而確定單位大小的像素個(gè)數(shù),我們就可以用絕對的單位,來規(guī)定軟件窗口的大小,例如長寬是多少毫米,或是多少英寸,然后實(shí)際設(shè)置時(shí)再轉(zhuǎn)換成像素的個(gè)數(shù)。在這種情況下,不管是什么物理大小屏幕,我們可以保證窗口的大小是一致的。第二種情況,如果我們無法確定輸出屏幕的絕對物理大小,那么我們也可以根據(jù)屏幕的分辨率,取一個(gè)相對比例,例如在1920*1080的分辨率,我們?nèi)》直媛实?/3,也就是1280*720像素大小,在這種情況下,我們一般也能保證不管屏幕的物理大小是14寸或是15寸,也可以保證軟件窗口的初始大小是適中的,不會因高分屏而顯得過小,而在普分屏的情況下,屏幕分辨率的2/3也是一個(gè)適中的數(shù)字,保證我們軟件窗體的大小是看起來舒適的,不會顯得過大或過小。
要實(shí)現(xiàn)這些功能,剛好在windows SDK中有一個(gè)API,GetDeviceCaps(HDC hDC,intindex),顧名思義,這個(gè)API可以了解設(shè)備的能力,也就是設(shè)備的一些功能參數(shù)。其中入口參數(shù)的hDC,是設(shè)備上下文(DeviceContext)的句柄,index是一個(gè)常量值索引,其中常見的命名符號常量值有:HORZSIZE、VERTSIZE、HORZRES、VERTRES、LOGPIXELSX、LOGPIXELSY等。其中采用HORZSIZE、VERTSIZE為索引可以取得物理屏幕的寬度和高度,以毫米為單位;以HORZRES、VERTRES為索引則可以取得屏幕的分辨率,以像素點(diǎn)為單位。
例如,我們?nèi)绻肴〉幂敵銎聊坏奈锢泶笮?,可以這樣來調(diào)用:
HDC hdcScreen=::GetDC(NULL);//取得屏幕的設(shè)備上下文句柄
int xMM=GetDeviccCaps(hdcScreen,HORZSIZE);
int yMM=GetDeviceCaps(hdcScreen,VERTSIZE);
現(xiàn)在xMM中就是以毫米為單位的顯示屏幕的寬度,yMM中就是以毫米為單位的顯示屏幕的高度;有了這兩個(gè)數(shù)值,再用參數(shù)索引HORZRES和VERTRES來調(diào)用GctDeviceCaps可以取得屏幕的分辨率,也就可以算出單位毫米的像素多少,間接用毫米為單位確定窗體大小。
但是,這樣得到的屏幕的大小并不是特別精確,存在一定的偏差;在windows7系統(tǒng)下,其偏差還比較大。這樣的話,我們可以直接采用第二種方案,采屏幕分辨率的2/3作為窗口的大小。
在VC環(huán)境下,我們可以重載窗口類的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 選擇適當(dāng)?shù)淖鴺?biāo)映射模式進(jìn)行繪圖輸出
我們在確定了軟件的主窗口的大小后,在窗口客戶區(qū)繪制輸出,為了方便靈活,同樣可以不采用直觀的像素單位,而以更接近實(shí)際的單位來進(jìn)行輸出;這樣,我們就需要調(diào)整坐標(biāo)映射模式。
在Windows應(yīng)用程序的開發(fā)中,文本、圖形的繪制函數(shù)采用的是一種邏輯坐標(biāo)系統(tǒng),而實(shí)際的設(shè)備輸出采用的是設(shè)備坐標(biāo)系統(tǒng)。設(shè)備坐標(biāo)以像素為單位,原點(diǎn)固定在窗口的左上角,向右的方向?yàn)閤軸正方向,向下的方向?yàn)閥軸正方向。將邏輯坐標(biāo)轉(zhuǎn)換成設(shè)備坐標(biāo),是通過設(shè)置所謂的坐標(biāo)映射模式來完成的。在windows系統(tǒng)中一共有八種坐標(biāo)映射模式,可以通過CDC類中SetMapMode(int nMapMode)方法來設(shè)置,其中nMapMode參數(shù)是一個(gè)整型值,不同的取值代表不同模式,可以取以下的常量值:
(1)MM_ANISOTROPIC。自定義的映射模式,這種映射模式在x方向和y方向均使用自定義的單位長度,并且兩個(gè)方向上的單位長度可以不一樣。
(2)MM_ISOTROPIC。自定義的映射模式,這種映射模式在x方向和y方向上使用相同的單位長度。
(3)MM_HHENGLISH。以0.001英寸為邏輯單位長度,向右的方向?yàn)閤軸正方向,向上的方向?yàn)閥軸正方向。
(4)MM_HIMETRIC。以0.01毫米為邏輯單位長度,向右的方向?yàn)閤軸正方向,向上的方向?yàn)閥軸正方向。
(5)MM_LOENGLISH。以0.01英寸為邏輯單位長度,向右的方向?yàn)閤軸正方向,向上的方向?yàn)閥軸正方向。
(6)MM_LOMETRIC。以0.1毫米為邏輯單位長度,向右的方向?yàn)閤軸正方向,向上的方向?yàn)閥軸正方向。
(7)MM_TEXT。以1設(shè)備像素為邏輯單位長度,向右的方向?yàn)閤軸正方向,向下的方向?yàn)閥軸正方向。在本坐標(biāo)模式下,邏輯單位和設(shè)備單位是一致的。
(8)MM_TWIPS。以1/20磅為邏輯單位長度,向右的方向?yàn)閤正方向,向上的方向?yàn)閥軸正方向。
這其中的MM_TExT坐標(biāo)映射模式是最直觀,最易于使用的一種坐標(biāo)映射模式,也是缺省的坐標(biāo)映射模式。在這樣的坐標(biāo)系統(tǒng)中,向右的方向?yàn)閤軸的正方向,向下的方向?yàn)閥軸的正方向。無論是x方向還是y方向,每一個(gè)單位長度都代表設(shè)備上的一個(gè)像素。這樣輸出函數(shù)的所用的邏輯坐標(biāo)和實(shí)際輸出的設(shè)備坐標(biāo)是相同的。這種映射模式在實(shí)際中也得到了較多的應(yīng)用,它又是缺省的映射模式,以至于很多人編程中都忘記了坐標(biāo)模式的映射這回事。當(dāng)然,它的問題也是很明顯的。不同的設(shè)備,同一個(gè)像素點(diǎn)的大小是不相同的。同樣一個(gè)14寸的筆記本電腦,在1366*768的分辨率下,150*150。大小的一個(gè)矩形,還可以輕松的分辨。但是在1920*1080的分辨率下,就未免顯得太小了,讓人看起來不舒服。
其他的幾種模式,是一種設(shè)備無關(guān)的映射模式。Windows繪圖輸出函數(shù)中使用的x值和y值這些坐標(biāo)是一種邏輯單位,它們表示的單位距離可以由用戶設(shè)定;而實(shí)際的輸出設(shè)備采用的x值和y值表示的單位距離是實(shí)際顯示設(shè)備上的像素點(diǎn)。其中,MM_LOMETRIC、MM_LOENGLISH等映射模式以0.1毫米、0.01英寸之類的絕對長度為單位,當(dāng)在不同的設(shè)備上輸出的時(shí)候,對應(yīng)的像素點(diǎn)個(gè)數(shù)是不相同的,將邏輯單位換算成設(shè)備單位由系統(tǒng)來自動完成。
因此如果采用MM_LOMETRIC模式,由于它的單位是0.1mm,所以在150*150大小的矩形實(shí)際上是1.5cm*1.5cm,至于在不同設(shè)備對應(yīng)到多少個(gè)像素,這個(gè)由windows系統(tǒng)幫我們來進(jìn)行轉(zhuǎn)換,系統(tǒng)保證在不同的輸出設(shè)備下,它都統(tǒng)一是1.5cm的一個(gè)矩形。下面的代碼采用MM_LOMETRIC映射模式在屏幕上輸出10毫米*10毫米的一個(gè)矩形。
CReet rt;
GetClientRect(rt);
pDC->SetViewPortorg(0,rt.Height());//設(shè)置邏輯坐標(biāo)的原點(diǎn)在設(shè)備坐標(biāo)上的位置是左下角
pDC->SetMaPMode(MM_LOMETRIC);//設(shè)置坐標(biāo)映射模式
pDC->Rectangle(CRect(0,0,100,100));
另外,我們也可以采用MM_ANISOTROPIC映射模式或MM_ISOTROPIC坐標(biāo)模式,這兩種模式可以自定義邏輯坐標(biāo)和設(shè)備坐標(biāo)的映射關(guān)系。其中MMA卜ISOTROPIC模式可以建立長和寬的邏輯坐標(biāo)與設(shè)備坐標(biāo)不同的映射關(guān)系,實(shí)現(xiàn)對繪制函數(shù)繪制的圖形在縱橫比上進(jìn)行任意的縮放。MM_IsoTRoPIe坐標(biāo)模式與MM_ANISOTROPIC坐標(biāo)模式不同,該坐標(biāo)模式也可以建立邏輯坐標(biāo)與設(shè)備坐標(biāo)不同的映射關(guān)系,實(shí)現(xiàn)對繪制函數(shù)繪制的圖形進(jìn)行比例縮放,但不會改變圖形的縱橫比。
MM_ANISOTROPIC和MM_ISOTROPIC這兩種映射模式需要設(shè)置邏輯單位和設(shè)備單位間的對應(yīng)(比例)關(guān)系,設(shè)置方法是定義兩個(gè)矩形,第一個(gè)矩形以邏輯單位表示進(jìn)行繪制的范圍大小,第二個(gè)矩形以設(shè)備單位(即像素)表示第一個(gè)矩形范圍代表的設(shè)備范圍大小,這樣就確定了邏輯單位和設(shè)備單位間的轉(zhuǎn)換關(guān)系。在Windows系統(tǒng)中,第一個(gè)矩形一般稱為窗口,而第二個(gè)矩形則稱為視口。設(shè)置窗口和視口位置及范圍的CDC成員如下:
SetViewportOrg((POINT point)//設(shè)置窗口坐標(biāo)的原點(diǎn)在設(shè)備坐標(biāo)上的位置
SetWindowExt(SIZE size)//設(shè)置窗口的大小
SetViewportExt(SIZE size)//設(shè)置視口的大小
實(shí)際應(yīng)用中,由于MM_ANISOTROPIC坐標(biāo)模式可以改變邏輯坐標(biāo)與設(shè)備坐標(biāo)間的比例關(guān)系,所以在應(yīng)用程序中可以先為窗口假定一個(gè)長、寬尺寸即設(shè)定邏輯尺寸,然后根據(jù)該尺寸繪制好圖形。當(dāng)窗口尺寸被改變即窗口物理尺寸發(fā)生變化時(shí),只要改變邏輯坐標(biāo)與設(shè)備坐標(biāo)間的比例關(guān)系,就可以使得窗口的邏輯尺寸依然不變,使得采用邏輯坐標(biāo)繪制的圖形在窗口內(nèi)的相對位置不變。
下面的代碼即采用MM_ANISOTROPIC映射坐標(biāo)模式輸出一個(gè)長寬為100個(gè)邏輯單位的矩形。
CRect elientRect;
GetClientReet(clientReet);
pDC->SetMaPMode(MM_ANISOTROPIC);
pDC->SetViewportOrg(0,0);//設(shè)置窗口坐標(biāo)的原點(diǎn)在設(shè)備坐標(biāo)上的左上角
pDC->SetWindowExt(500,500);//設(shè)置窗口的范圍
pDC->SetViewportExt(clientRect.right,clientRect.bottom);//對應(yīng)窗口范圍的實(shí)際設(shè)備輸出范圍
pDC->Rectangle(CRect(0,0,100,100));
4 結(jié)論
綜上所述,我們在編程時(shí),設(shè)置窗口的大小和圖形、文本的繪制輸出時(shí),不是單純的方便省事,采用像素為單位,而是根據(jù)輸出屏幕的大小,采用更為自然和實(shí)際的輸出坐標(biāo)單位,將更能讓輸出的結(jié)果適應(yīng)于不同大小和分辨率的屏幕,讓最終顯示效果更為自然、協(xié)調(diào)和一致。