建立一個合適的
坐標(biāo)系可以為我們的繪圖帶來很大的方便 。下面介紹一下如何在VC中建立我們想要的坐標(biāo)系。
一 設(shè)備坐標(biāo)和邏輯坐標(biāo)
設(shè)備坐標(biāo)(Device Coordinate)又稱為物理坐標(biāo)(Physical Coordinate),是指輸出設(shè)備上的坐標(biāo)。通常將屏幕上的設(shè)備坐標(biāo)稱為屏幕坐標(biāo)。設(shè)備坐標(biāo)用對象距離窗口左上角的水平距離和垂直距離來指定對象的位置,是以像素為單位來表示的,設(shè)備坐標(biāo)的X軸向右為正,Y軸向下為正,坐標(biāo)原點(diǎn)位于窗口的左上角。
邏輯坐標(biāo)(Logical Coordinate)是系統(tǒng)用作記錄的坐標(biāo)。在缺省的模式(MM_TEXT)下,邏輯坐標(biāo)的方向和單位與設(shè)備坐標(biāo)的方向和單位相同,也是以像素為單位來表示的,X軸向右為正,Y軸向下為正,坐標(biāo)原點(diǎn)位于窗口的左上角。邏輯坐標(biāo)和設(shè)備坐標(biāo)即使在缺省模式下其數(shù)值也未必一致,除了在以下兩種情況下:
1. 窗口為非滾動窗口
2. 窗口為滾動窗口,但垂直滾動條位于滾動邊框的最上端,水平滾動條位于最左端,但如果移動了滾動條這兩種坐標(biāo)就不一致了。
在VC中鼠標(biāo)坐標(biāo)的坐標(biāo)位置用設(shè)備坐標(biāo)表示,但所有GDI繪圖都用邏輯坐標(biāo)表示,所以用鼠標(biāo)繪圖時,那么必須將設(shè)備坐標(biāo)轉(zhuǎn)換為邏輯坐標(biāo),可以使用CDC 函數(shù)DptoLP()將設(shè)備坐標(biāo)轉(zhuǎn)化為邏輯坐標(biāo),同樣可以用LptoDP()將邏輯坐標(biāo)轉(zhuǎn)化為設(shè)備坐標(biāo)。
二 坐標(biāo)模式
為了在不同的領(lǐng)域使用邏輯坐標(biāo),Windows提供了以下8種坐標(biāo)模式:
分別為MM_TEXT、MM_HIENGLISH、MM_LOENGLISH、MM_HIMETRIC、MM_LOMETRIC、MM_TWIPS、MM_ANISOTROPIC和MM_ISOTROPIC。
三 實(shí)例解析
(一) 建立以左上角為原點(diǎn),X軸和Y軸為1000的坐標(biāo),如下圖
我們可以用以下代碼:
void CTtView::OnDraw(CDC* pDC)
{
CTtDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CRect rect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetViewportOrg(0,0);
pDC->SetViewportExt(rect.right,rect.bottom);
pDC->SetWindowOrg(0,0);
pDC->SetWindowExt(1000,1000);
pDC->MoveTo(50,50);
pDC->LineTo(50,950);
pDC->LineTo(950,950);
pDC->LineTo(50,50);
}
代碼分析:
1. GetClientRect(&rect); 取得客戶區(qū)矩形區(qū)域,將其存放在rect中
2. 用pDC->SetMapMode(MM_ANISOTROPIC); 設(shè)置映射模式
3. 通過pDC->SetViewportOrg(0,0);設(shè)置邏輯坐標(biāo)的原點(diǎn)。
4. 通過pDC->SetViewportExt(rect.right,rect.bottom);和
pDC->SetWindowExt(1000,1000);來確定邏輯坐標(biāo)下和設(shè)備坐標(biāo)下的尺寸對應(yīng)關(guān)系
5. 在MM_ANISOTROPIC模式下,X軸單位和Y軸單位可以不相同
6. 坐標(biāo)方向的確定方法是如果邏輯窗范圍和視口范圍符號相同,則邏輯坐標(biāo)的方向和視口的方向相同,即X軸向右為正,Y軸向下為正。
7. 如果將顯示模式改為MM_ISOTROPIC,那么X軸單位和Y軸單位一定相同,感興趣的讀者可以自己使一下。
(二) 建立以視窗中心為原點(diǎn)的坐標(biāo),如下:
用如下代碼:
void CTtView::OnDraw(CDC* pDC)
{
CTtDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CRect rect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetViewportOrg(rect.right/2,rect.bottom/2);
pDC->SetViewportExt(rect.right,rect.bottom);
pDC->SetWindowOrg(0,0);
pDC->SetWindowExt(1000,-1000);
pDC->MoveTo(150,150);
pDC->LineTo(-150,-200);
pDC->LineTo(150,-150);
pDC->LineTo(150,150);
}
代碼分析:
1. 用 pDC->SetViewportOrg(rect.right/2,rect.bottom/2); 設(shè)置視口的原點(diǎn)。
2. 用pDC->SetViewportExt(rect.right,rect.bottom);和pDC->SetWindowExt(1000,-1000);來確定設(shè)備坐標(biāo)和邏輯坐標(biāo)的單位對應(yīng)關(guān)系。
3. 因?yàn)檫壿嫶胺秶鸵暱诜秶姆柌灰恢拢v坐標(biāo)取反,所以Y軸向上為正。
MM_LOENGLISH、MM_HIENGLISH、MM_LOMETRIC、MM_HIMETRIC、MM_TWIPS這一組是Windows提供的重要的固定比例映射模式。
它們都是x值向右方向遞增,y值向下遞減,并且無法改變。它們之間的區(qū)別在于比例因子見下:(我想書上P53頁肯定是印錯了,因?yàn)橥ㄟ^程序?qū)嶒?yàn)x值向右方向也是遞增的)
MM_LOENGLISH 0.01英寸
MM_HIENGLISH 0.001英寸
MM_LOMETRIC 0.1mm
MM_HIMETRIC 0.01mm
MM_TWIPS 1/1440英寸 //應(yīng)用于打印機(jī),一個twip相當(dāng)于1/20磅,一磅又相當(dāng)于1/72英寸。
在VC里, 準(zhǔn)確的說是在Windows編程中,映射模式有:MM_TEXT,(設(shè)備坐標(biāo))
MM_HIMETRIC,(邏輯坐標(biāo))
MM_ISOTROPIC,MM_ANISOTROPIC,.....在的開發(fā)環(huán)境下,(Windows 默認(rèn)的模式是MM_TEXT),我們可以通過SetMapMode()來改變當(dāng)是的映射模式~
MM_TEXT :X向右方向遞增加,Y向下方向遞增加,我們可以通過SetViewportOrg()和SetWindowOrg()來改變坐標(biāo)原點(diǎn)的位置.
void CInSide_VCView::OnDraw(CDC* pDC)
{
pDC->TextOut (0,0,"TEST");
pDC->SelectStockObject (GRAY_BRUSH);
pDC->SetMapMode (MM_TEXT);
//pDC->SetWindowOrg (100,100); 交替使用這兩句看有什么現(xiàn)象
//pDC->SetViewportOrg(CPoint(100,100));
pDC->Ellipse (CRect(0,0,300,300));
pDC->TextOut (0,0,"22");
}
固定比例模式:X向右方向遞減(我認(rèn)為是增加),Y向下方向遞減,MM_LOENGLISH(0.01英寸) MM_HIENGLISH(0.001英寸) MM_LOMETRIC(0.1mm) MM_HIMETRIC(0.01mm) MM_TWIPS(1/1400英寸,一般用于打印機(jī))
可變比例模式:M_ISOTROPIC(1:1),MM_ANISOTROPIC(可為任意比例),用SetWindowsExt() 和SetViewportExt()來設(shè)定比例,
void CInSide_VCView::OnDraw(CDC* pDC)
{
CRect rectClient;
GetClientRect(rectClient);
pDC->SelectStockObject (m_nColor);
pDC->SetMapMode (MM_ANISOTROPIC);
pDC->SetWindowExt (1000,1000);
pDC->SetViewportExt (rectClient.right,rectClient.bottom );
pDC->SetViewportOrg (rectClient.right/2,rectClient.bottom/2);
pDC->Ellipse (CRect(-500,-500,500,500));
}
物理坐標(biāo),即我們現(xiàn)實(shí)中的尺寸,屏幕中一英寸是現(xiàn)實(shí)中的12英寸,如果我們使用MM_LOENGLISH(0.01英寸)的映射模式,那么26.75英寸將是電腦的26.75/12=2.23(英寸),在電腦里1個邏輯單位是0.01英寸,所以,26.75英寸轉(zhuǎn)換為邏輯單位是223單位,但是這過程中有省略,為了防止這樣的情況,我們可以使用物理坐標(biāo)保存。
轉(zhuǎn)換函數(shù);DPtoLP() 設(shè)備坐標(biāo)到邏輯坐標(biāo); LPtoDP()邏輯坐標(biāo)到設(shè)備坐標(biāo);物理坐標(biāo)到邏輯坐標(biāo)的轉(zhuǎn)換全是由我們自己計算;
MFC 中一般情況下有下面的情況:
CDC類中的所有成員函數(shù)用的是邏輯坐標(biāo)做參數(shù)
CWND類中的所有成員函數(shù)用的是設(shè)備坐標(biāo)做參數(shù)
所有的選中-測試(HIT-TEST)操作都是用的設(shè)備坐標(biāo),有些函數(shù)只能使用設(shè)備坐標(biāo)如:CRect::PtInRect()
所有要長期保存的值一般用邏輯坐標(biāo),用設(shè)備坐標(biāo)則用戶對窗口滾動就會改變,該坐標(biāo)就會失效了;
下一例子,測試鼠標(biāo)左鍵點(diǎn)的區(qū)域是不是在指定的地方
void CMyView::OnLButtonDown(UINT uFlags,CPoint point)
{
CRect rect=m_rect;
CClientDC dc(this);
dc.SetMapMode(MM_TEXT);
dc.LPtoDP(rect);
if(rect.PtInRect(point))
{
MessageBox("YES");
}
}
一般設(shè)置映射模式在OnPrepareDC() 中比較合適~,OnPrepareDC在OnDraw前調(diào)用!
MFC 對140 種Windows 消息提供了直接的消息控制函數(shù),特別注意下面5個:WM_CREATE,WM_CLOSE,WM_DESTROY,WM_NCDESTROY,WM_QUERYENDSESSION.
WM_CREATES 是WINDOWS 發(fā)送給視圖的第一個消息,所以在OnCreate()中不能調(diào)用那寫依賴窗口完全處于激活的WINDOWS函數(shù)!,一般來說可以在 OnInitialUpdate()中調(diào)用,如:設(shè)置映射模式~,但是必須注意,OnInitialUpdate()在視圖生存之間可能被調(diào)用多次~