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