[MFC] 控制元件大小跟隨對話方塊大小比例變化 [大三TJB_708]
網上查閱有多種方法,選學一種筆記如步驟下。
1 搭建完成控制元件隨對話方塊變化比例變化的框架
1.1 在對話方塊類中的訊息對映巨集中新增對話方塊尺寸改變時的訊息巨集
[cpp] view plaincopyprint?- BEGIN_MESSAGE_MAP( theClass, baseClass )
- ON_WM_SIZE()
- END_MESSAGE_MAP()
ON_VM_SIZE訊息,此訊息(VC定義的巨集)表示只要視窗大小發生變化時就係統就自動呼叫此訊息對應的函式OnSize(UINT nType, intcx, int cy)。
VM_SIZE訊息巨集對應的訊息如下表所列舉:
SIZE_MAXHIDE 4 |
Message is sent to all pop-up windows when some other window is maximized.當有視窗最大化時,此訊息傳送給所有在上層的視窗,告之隱藏。 |
SIZE_MAXIMIZED2 |
The window has been maximized.當視窗已經被最大化後。 |
SIZE_MAXSHOW3 |
Message is sent to all pop-up windows when some other window has been restored(恢復) to its former size. |
SIZE_MINIMIZED1 |
The window has been minimized. |
SIZE_RESTORED0 |
The window has been resized, but neither the SIZE_MINIMIZED norSIZE_MAXIMIZED value applies. |
1.2 因為此訊息巨集對應的唯一函式為OnSize,所以在新增此訊息後需要到.cpp檔案中編寫此函式,實現目標功能的程式碼
1.3 在編寫此函式時(前 | 後 )需要到對話方塊繼承類中宣告此函式
2 實現目標功能
2.1 首先在對話方塊的OnInitDialog函式中獲取對話方塊客戶區的大小
[cpp] view
plaincopyprint?
- CRect rect;
- GetClientRect(&rect);
- oSize.x = rect.right - rect.left;
- oSize.y = rect.bottom - rect.top;
此處GetClientRect函式的原型為:
void GetClientRect(
LPRECT lpRect
) const;
函式功能:將CWnd類視窗的客戶區域的座標賦值到lpRect所指的結構體中。
引數含義:指向RECT型別的結構體或者CRect物件接受客戶區域的座標。此引數的left和top成員的值將會是0,right和bottom成員的值包含了視窗客戶區域的寬度和高度。
oSize是在繼承對話方塊類中的資料成員,型別為POINT。根據lpRect引數含義,後面的兩行語句就記住了窗體客戶區域的寬度和高度。
2.2 過載OnSize函式
[cpp] view plaincopyprint?- //-------------------------------------------------
- //對話方塊尺寸變化時,對話方塊內的控制元件隨之改變大小函式
- //--------------------------------------------------
- void CDMarriageMatchDlg::OnSize(UINT nType, int cx, int cy)
- {
- CDialogEx::OnSize(nType, cx, cy);
- if (nType==SIZE_RESTORED || nType==SIZE_MAXIMIZED)
- {
- float ratio[2];
- POINT newDialogSize;
- CRect newRect;
- //獲取新的客戶區的大小
- GetClientRect(&newRect);
- newDialogSize.x = newRect.right - newRect.left;
- newDialogSize.y = newRect.bottom - newRect.top;
- //得現在的對話方塊與以往對話方塊的大小比例
- ratio[0] = (float)newDialogSize.x / oSize.x;
- ratio[1] = (float)newDialogSize.y / oSize.y;
- CRect Rect;
- int woc;
- //左右上角的資料
- CPoint OldTLPoint, NewTLPint;
- CPoint OldBRPoint, NewBRPint;
- //列出所有控制元件
- HWND hwndChild = ::GetWindow(m_hWnd,GW_CHILD);
- while(hwndChild)
- {
- //取得ID
- woc = ::GetDlgCtrlID(hwndChild);
- GetDlgItem(woc)->GetWindowRect(Rect);
- ScreenToClient(Rect);
- OldTLPoint = Rect.TopLeft();
- NewTLPint.x = long(OldTLPoint.x*ratio[0]);
- NewTLPint.y = long(OldTLPoint.y*ratio[1]);
- OldBRPoint = Rect.BottomRight();
- NewBRPint.x = long(OldBRPoint.x*ratio[0]);
- NewBRPint.y = long(OldBRPoint.y*ratio[1]);
- Rect.SetRect(NewTLPint,NewBRPint);
- GetDlgItem(woc)->MoveWindow(Rect,TRUE);
- hwndChild=::GetWindow(hwndChild, GW_HWNDNEXT);
- }
- //獲取視訊視窗父視窗的大小
- ::GetClientRect(hWnd, &grc);
- oSize = newDialogSize;
- }
- }
(1) 在此函式中的GetClientRect表示在視窗有變動時就會在視窗改變尺寸( 以非SIZE_MINIMIZED norSIZE_MAXIMIZED 時)或者視窗已經最大化的情況下重新獲取視窗的尺寸並獲得視窗的寬度和高度。
(2) 獲取對話方塊中的所有控制元件
實現這一個功能利用window函式,函式原型為:
HWND WINAPI GetWindow(
_In_ HWND hWnd,
_In_ UINT uCmd
);
函式功能:檢索hWnd所指向的視窗與特殊視窗cCmd之間的關係。
引數:hWnd索要檢測的父視窗。
uCmd父視窗中的所屬控制元件型別( 與hWnd視窗的關係,具體引數含義在VS2010中 按F1查詢 )。
程式中的m_hWnd表示對話方塊(當對話方塊是所有的視窗最上面那個的時候 ),GW_CHILD表示當前最上面視窗的子視窗( 如對話方塊內的控制元件 )。
(3) 在用GetWindow獲取hWnd(對話方塊 )內子視窗( 控制元件 )成功時,就進入while中進行下一步操作。
第一步是用GetDlgCtrlID函式獲取此控制元件的識別符號,此函式有唯一的引數,就是此控制元件的控制代碼( 由GetWindow函式返回 如hwndChild)。
第二步是利用GetDlgItem(F1)函式返回指向控制元件或子視窗的指標,並用此指標訪問GetWindowRect方法,目的是獲取到指標所指向控制元件( 猜:此指標已屬此控制元件定義的一種指標物件 )的尺寸大小,並返回給GetWindowRect中的引數Rect。
第三步是利用ScreenToClient函式將獲取的尺寸轉換成客戶區的尺寸。ScreenToClient函式的引數可為POINT或者CRect型別。此程式為CRect型別。
第四步是計算對話方塊尺寸改變後控制元件在客戶區的新座標。由對話方塊整個客戶區改變的比例(新座標比上舊座標 )來確定對話方塊中的控制元件的座標應該怎麼變化:控制元件的新座標與整個對話方塊成比例變化。所以就得到了控制元件的新座標:
[cpp] view plaincopyprint?- OldTLPoint = Rect.TopLeft();
- NewTLPint.x = long(OldTLPoint.x*ratio[0]);
- NewTLPint.y = long(OldTLPoint.y*ratio[1]);
- OldBRPoint = Rect.BottomRight();
- NewBRPint.x = long(OldBRPoint.x*ratio[0]);
- NewBRPint.y = long(OldBRPoint.y*ratio[1]);
第五步是用CRect::SetRect方法設定CRect特定的座標。
第六步是利用將當前控制元件的MoveWindow方法將控制元件的位置移到新設定的座標之上。
void MoveWindow(
LPCRECT lpRect,
BOOL bRepaint = TRUE
);
第一個引數即是CRect物件或者RECT結構體指定的新座標。
第六步就hwndChild=::GetWindow(hwndChild,GW_HWNDNEXT);可單純的認為是獲取對話方塊內下一個子控制元件。
如此迴圈,就將對話方塊內的所有的控制元件都按照對話方塊尺寸變化給變化完成了。
第7步:等對話方塊中所有的控制元件都變化完畢之後,對話方塊的大小要更新為當前對話方塊的大小,這個理念,做過程式設計的都懂。下次對話方塊尺寸再發生變化時,就在oSize的基礎之上在執行此函式中的程式碼,對話方塊內控制元件隨對話方塊成比例變化功能完成。
此次筆記記錄完畢。