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