VC++技術內幕(第四版)筆記--SetWindowExt和SetViewportExt
CRect rectClient;
GetClientRect(rectClient);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(CSize(1000,1000));
pDC->SetViewportExt(rectClient.right,-rectClient.bottom);
pDC->SetViewportOrg(rectClient.right/2,rectClient.bottom/2);
pDC->Ellipse(-500,-500,500,500);
可變比例映射模式,看到這一段的時候,一開始就把我的弄煳塗了。我一直沒弄明白中間加紅的幾行代碼是什麼意思。把其注釋掉,又沒有原先的效果。在網上百度了半天。得出以下注釋說明:
//SetWindowExe設定窗口尺寸,SetViewportExt設定視口尺寸。
//窗口尺寸以邏輯單位計算,視口尺寸以物理單位計算。
CRect rectClient;
GetClientRect(rectClient);//取窗口物理尺寸(單位:像素)
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(1000, 1000);//窗口邏輯大小:1000*1000,
pDC->SetViewportExt(rectClient.right, -rectClient.bottom);//改變Y坐標方向--viewport使用物理大小
pDC->SetViewportOrg(rectClient.right / 2, rectClient.bottom / 2);//設置窗口中心點為坐標係原點--Viewport使用物理大小
pDC->Ellipse(CRect(-500, -500, 500, 500));//以邏輯單位畫圖---普通GDI API使用邏輯單位
//默認方式下,物理/邏輯值是1:1關係,可換用。但使用SetWindowExt/SetViewportExt後兩者不可混用。
以上紅色部分,我的解釋是以物理的原點為坐標係,以邏輯的大小為單位畫圓。後麵的代碼中會說明這一問題。
後來經過自己的捉摸,我想我終於搞清楚是怎麼一回事情了。
所謂映射就是物理和邏輯的映射。使用GetClientRect方法後,獲取到窗口的物理大小;然後再使用SetWindowExt,設置了窗口的邏輯大小,與之相對應的是SetViewportExt,也就是說在這裏作了一個映射。SetWindowExt中的第一個參數
cx
Specifies the x-extent (in logical units) of the window.
X寬度(可以這麼理解嗎?)與 SetViewportExt中的第一個參數
Cx
Specifies the x-extent of the viewport (in device units).
相對應起來。好像中學的比例一樣。邏輯寬度和物理寬度映射,邏輯高度和物理高度映射。這樣,一旦映射關係確立之後,再使用後麵的方法進一步的操作。
一開始的代碼是在窗口中顯示一個與之限定的圓,並且會隨著窗口大小的改變亦會跟著改變。
我現在稍稍把其中的參數改變一下。
CRect rectClient;
GetClientRect(rectClient);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(CSize(800,800));
pDC->SetViewportExt(rectClient.right,-rectClient.bottom);
pDC->SetViewportOrg(rectClient.right/2,rectClient.bottom/2);
pDC->Ellipse(-500,-500,500,500);
注意上麵紅色突出顯示的代碼。我現在將邏輯大小變小了一些。現在注意一下實際在畫圖的代碼中(綠色顯示),我並沒有修改其參數。現在將其編譯運行。會發現,實現中的圓的軌跡會超出窗口。
隻是把物理與邏輯之前的映射調整了一下。
CRect rectClient;
GetClientRect(rectClient);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(CSize(1000,1000));
pDC->SetViewportExt(rectClient.right,-rectClient.bottom);
pDC->SetViewportOrg(rectClient.right/2,rectClient.bottom/2);
pDC->Ellipse(0,0,500,500);
再調整一下參數,畫出來的圖你會發現,真正的成了二維坐標圖。
經過以上一番測試,我想我應該明白每行代碼的意思了。轉換成自己的注釋,應該更容易理解和記憶些。
CRect rectClient;
GetClientRect(rectClient); //獲取物理設備大小
pDC->SetMapMode(MM_ANISOTROPIC); //設置映射模式
pDC->SetWindowExt(CSize(1000,1000)); //設備邏輯窗口大小(可能與物理窗口大小不一樣)
pDC->SetViewportExt(rectClient.right,-rectClient.bottom); //設置物理設備範圍,為設定圓點作準備
pDC->SetViewportOrg(rectClient.right/2,rectClient.bottom/2); //設置物理設備坐標原點,當然是在上一行代碼的基礎之上
pDC->Ellipse(-500,-500,500,500); //以物理設置坐標原點為基礎,以邏輯為單位,畫圓。
可以改造一下,原來的代碼,使之後容易理解一些:
CRect rectClient;
GetClientRect(rectClient);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(CSize(1000,1000));
pDC->SetViewportExt(rectClient.right,-rectClient.bottom);
pDC->SetViewportOrg(rectClient.left,rectClient.bottom); //設置窗口左下角為原點坐標
pDC->Ellipse(0,0,1000,1000);
最後更新:2017-04-02 06:51:27