映射模式:MM--Mapping Modes

http://smycll.blog.hexun.com/74080279_d.html


映射模式

   在此篇之前我們已經學會了在窗口顯示圖形,更準確的說是在窗口指定位置顯示圖形或文字,我們使用的座標單位是象素,稱之爲設備座標。看下面語句:

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

   畫一個高和寬均爲200個象素的方塊,因爲採用的是默認的MM_TEXT映射模式,所以在設備環境不一樣時,畫的方塊大小也不一樣,在1024*768的顯示器上看到的方塊會比640*480的顯示器上的小(在不同分辨率下的屏幕象素,在WINDOWS程序設計一書中有示例程序可以獲得,或者可以用GetClientRect函數獲得客戶區的矩形大小。在這裏就不說了,大家只要知道就行了),在輸出到打印機時也會有類似的情況發生。如何做才能保證在不同設備上得到大小一致的方塊或者圖形、文字呢?就需要我們進行選擇模式映射,來轉換設備座標和邏輯座標。

Windows提供了以下幾種映射模式:

MM_TEXT 
MM_LOENGLISH 
MM_HIENGLISH 
MM_LOMETRIC 
MM_HIMETRIC 
MM_TWIPS 
MM_ISOTROPIC 
MM_ANISOTROPIC

下面分別講講這幾種映射模式:

MM_TEXT:

   默認的映射模式,把設備座標被映射到象素。x值向右方向遞增;y值向下方向遞增。座標原點是屏幕左上角(0,0)。但我們可以通過調用CDC的SetViewprotOrg和SetWindowOrg函數來改變座標原點的位置看下面兩個例子:

//************************************************ 
// 例子6-1 
void CMyView::OnDraw(CDC * pDC) 

pDC->Rectangle(CRect(0,0,200,200));//全部採用默認畫一個寬和高爲200象素的方塊 
}

//************************************************** 
// 例子6-2 
void CMyView::OnDraw(CDC * pDC) 

pDC->SetMapMode(MM_TEXT);//設定映射模式爲MM_TEXT 
pDC->SetWindowOrg(CPoint(100,100));//設定邏輯座標原點爲(100,100) 
pDC->Rectangle(CRect(100,100,300,300));//畫一個寬和高爲200象素的方塊 
}

   這兩個例子顯示出來的圖形是一樣的,都是從屏幕左上角開始的寬和高爲200象素的方塊,可以看出例子2將邏輯座標(100,100)映射到了設備座標(0,0)處,這樣做有什麼用?滾動窗口使用的就是這種變換。

固定比例映射模式:

MM_LOENGLISH、MM_HIENGLISH、MM_LOMETRIC、MM_HIMETRIC、MM_TWIPS這一組是Windows提供的重要的固定比例映射模式。

它們都是x值向右方向遞增,y值向下遞減,並且無法改變。它們之間的區別在於比例因子見下:(我想書上P53頁肯定是印錯了,因爲通過程序實驗x值向右方向也是遞增的)

MM_LOENGLISH 0.01英寸 
MM_HIENGLISH 0.001英寸 
MM_LOMETRIC 0.1mm 
MM_HIMETRIC 0.01mm 
MM_TWIPS 1/1440英寸 //應用於打印機,一個twip相當於1/20磅,一磅又相當於1/72英寸。

看例3

//************************************************** 
// 例子6-3 
void CMyView::OnDraw(CDC * pDC) 

pDC->SetMapMode(MM_HIMETRIC);//設定映射模式爲MM_HIMETRIC 
pDC->Rectangle(CRect(0,0,4000,-4000));//畫一個寬和高爲4釐米的方塊 
}

   還有一種是可變比例映射模式,MM_ISOTROPIC、MM_ANISOTROPIC。用這種映射模式可以做到當窗口大小發生變化時圖形的大小也會相應的發生改變,同樣當翻轉某個軸的伸展方向時圖象也會以另外一個軸爲軸心進行翻轉,並且我們還可以定義任意的比例因子,怎麼樣很有用吧。 
MM_ISOTROPIC、MM_ANISOTROPIC兩種映射模式的區別在於MM_ISOTROPIC模式下無論比例因子如何變化縱橫比是1:1而M_ANISOTROPIC模式則可以縱橫比獨立變化。

讓我們看例子4

//************************************************** 
// 例子6-4 
void CMy002View::OnDraw(CDC* pDC) 

CRect rectClient; // 
GetClientRect(rectClient);//返回客戶區矩形的大小 
pDC->SetMapMode(MM_ANISOTROPIC);//設定映射模式爲MM_ANISOTROPIC 
pDC->SetWindowExt(1000,1000); 
pDC->SetViewportExt (rectClient.right ,-rectClient.bottom ); 
//用SetWindowExt和SetViewportExt函數設定窗口爲1000邏輯單位高和1000邏輯單位寬 
pDC->SetViewportOrg(rectClient.right/2,rectClient.bottom/2 );//設定邏輯座標原點爲窗口中心 
pDC->Ellipse(CRect(-500,-500,500,500));//畫一個撐滿窗口的橢圓。 
// TODO: add draw code for native data here 
}

怎麼樣,屏幕上有一個能跟隨窗口大小改變而改變的橢圓。把 pDC->SetMapMode(MM_ANISOTROPIC);這句改爲pDC->SetMapMode(MM_ISOTROPIC)會怎樣?大家可以試試。那還有一個問題就是上例的比例因子是多少呢?看下面公式(注意是以例子4爲例的)

x比例因子=rectClient.right/1000 //視窗的寬除以窗口範圍 
y比例因子=-rectClient.bottom/1000 //視窗的高除以窗口範圍

   從Windows的鼠標消息可以獲得鼠標指針的當前座標值(point.x和point.y)此座標值是設備座標。

很多MFC庫函數尤其是CRect的成員函數只能工作在設備座標下。 
還有我們有時需要利用物理座標,物理座標的概念就是現實世界的實際尺寸。 
設備座標-邏輯座標-物理座標之間如何進行轉換便成爲我們要考慮的一個問題,物理座標和邏輯座標是完全要我們自己來做的,但WINDOWS提供了函數來幫助我們轉換邏輯座標和設備座標。

CDC的LPtoDP函數可以將邏輯座標轉換成設備座標 
CDC的DPtoLP函數可以將設備座標轉換成邏輯座標

下面列出我們應該在什麼時候使用什麼樣的座標系一定要記住:

◎CDC的所有成員函數都以邏輯座標爲參數 
◎CWnd的所有成員函數都以設備座標爲參數 
◎區域的定義採用設備座標 
◎所有的選中測試操作應考慮使用設備座標。 
◎需要長時間使用的值用邏輯座標或物理座標來保存。因設備座標會因窗口的滾動變化而改變。 
用書上的例子作爲以前幾篇的複習,如果你能夠獨立完成它說明前面的內容已經掌握。另外有些東西是新的,我會比較詳細的做出說明,例如客戶區、滾動窗口等。

下面我們來一步步完成例子6-5:

■第一步:用AppWizard創建MyApp6。除了Setp 1 選擇單文檔視圖和Setp 6 選擇基類爲CScrollView外其餘均爲確省。

■第二步:在CMyApp6View類中增加m_rectEllipse和m_nColor兩個私有數據成員。你可以手工在myapp6View.h添加,不過雷神建議這樣做,在ClassView中選中CMyApp6View類,擊右鍵選擇Add Member Variable插入它們。

//************************** 
// myapp6View.h 
private: 
int m_nColor; //存放橢圓顏色值 
CRect m_rectEllipse; //存放橢圓外接矩形

//***************************************************

問題1: CRect是什麼? 
CRect是類,是從RECT結構派生的,和它類似的還有從POINT結構派生的CPoint、從SIZE派生的CSize。因此它們繼承了結構中定義的公有整數數據成員,並且由於三個類的一些操作符被重載所以可以直接在三個類之間進行類的運算。 
//重載operator + 
CRect operator +( POINT point ) const; 
CRect operator +( LPCRECT lpRect ) const; 
CRect operator +( SIZE size ) const; 
//重載operator - 
CRect operator -( POINT point ) const; 
CRect operator -( SIZE size ) const; 
CRect operator -( LPCRECT lpRect ) const; 
...... 
更多的請在MSDN中查看

■第三步:修改由AppWizard生成的OnIntitalUpdate函數

void CMyApp6View::OnInitialUpdate() 

CScrollView::OnInitialUpdate(); 
CSize sizeTotal(20000,30000); 
CSize sizePage(sizeTotal.cx /2,sizeTotal.cy /2); 
CSize sizeLine(sizeTotal.cx /50,sizeTotal.cy/50); 
SetScrollSizes(MM_HIMETRIC,sizeTotal,sizePage,sizeLine);//設置滾動視圖的邏輯尺寸和映射模式 
}

問題2: 關於void CMyApp6View::OnInitialUpdate()

函數OnInitialUpdate()是一個非常重要的虛函數,在視圖窗口完全建立後框架用的第一個函數,框架在第一次調用OnDraw前會調用它。因此這個函數是設置滾動視圖的邏輯尺寸和映射模式的最佳地點。

■第四步:編輯CMyApp6View構造函數和OnDraw函數

//********************************************* 
// CMyApp6View構造函數 
// 
CMyApp6View::CMyApp6View():m_rectEllipse(0,0,4000,-4000)//橢圓矩形爲4*4釐米。 

m_nColor=GRAY_BRUSH;//設定刷子顏色 
}

//************ 
本文來自: 站長(http://www.qqcf.com) 詳細出處參考:http://study.qqcf.com/web/189/21186.htm


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章