MFC控件自適應(Resizer.h,Resizer.cpp)用法介紹
Every GUI developer uses dialogs. Sometimes, dialogs should support resizing to make the user's life easier. To create a resizable dialog, you just need to handle a WM_SIZE message and resize/move child controls. But, when a dialog contains many controls, resizing it would be a pain for the developer, and the OnSize function will look like a monster!
每個界面開發人員都會用到對話框,對話框類有時候應該支持動態調整大小,這樣可以讓用戶使用起來稍微方便些。要創建一個可調整大小的對話框,你應該處理一下WM_SIZE消息,并且調整/移動子控件。但是如果一個對話框中包含大量的控件,動態調整就是件痛苦的工作,OnSize函數也會變得異常臃腫。
When I ran into this problem, I wrote a simple resizer that could help significantly in making resizable dialogs. All you have to do now is:
- Create a dialog resource and position the controls as you wish.
- Make CResizer m_resizer a member of your dialog class.
- Initialize the resizer in OnInitDialog (m_resizer.Init(...)).
- Move controls in OnSize simply by calling m_resizer.Move()!
1、創建一個對話框資源,然后把它放置到你希望放置到位置。
2、在需要做動態調整的對話框中加入CResizer m_resizer類。
3、在OnInitDialog 函數中初始化(m_resizer.Init(...))。
4、在OnSize 函數中調用m_resizer.Move()!
Let's consider the implementation of CResizer class in detail.
讓我們考慮下CResizer 類的具體實現。
The main idea is the following: Each side of a child window (left, top, right, and bottom) is connected to a side of another window, the so-called relative window. The dialog window that owns the children also can be a relative window. When the dialog window is resized, the child window sides are moved after the relative window, thus preserving the connections.
主要思路如下:每個子窗口的邊 (左,上, 右,和底)都和另外一個窗口的邊相連,這就是所謂的相關窗口。包含子窗口的對話框窗口也可以是相關窗口。當對話框窗口大小變化后,子窗口的邊也會相應移動,以此確保相關性。
There are several types of connections:
有以下幾種關聯方式:
| Connection Type | Constant Name | Description |
| Fixed | CResizer::eFixed | Preserves the distance between the side of the child window and the specified side of the relative window |
| Proportional | CResizer::eProportional | Preserves the ratio of distance between the side of the child window and left (top) side of the relative window to width (height) of the relative window. |
| Preserving width | CResizer::eWidth | An auxiliary connection that preserves the width of the specified child window. It also can be implemented with a fixed connection. |
| Preserving height | CResizer::eHeight | An auxiliary connection that preserves the height of the specified child window. It also can be implemented with a fixed connection. |
| 關聯類型 | 常量名稱 | 描述 |
| 固定值 | CResizer::eFixed | 確保子窗口邊框和相關窗口的指定邊的距離不變 |
| 按比例 | CResizer::eProportional | 確保子窗口與左(上)方的相關窗口的距離與相關窗口的寬(高)比例不變。 |
| 寬度不變 | CResizer::eWidth | 這種連接方式比較靈活,指定的子窗口寬度不變。這種方式也可通過固定值方式實現。 |
| 高度不變 | CResizer::eHeight | 這種連接方式比較靈活,指定的子窗口高度不變。這種方式也可通過固定值方式實現。 |
The connections for child windows are specified in a static array of the CResizer::CBorderInfo structures. The format is as follows:
這些子窗口的關聯關系可以通過CResizer::CBorderInfo 的一個靜態結構體來指定格式如下:
- {IDC_CTRL_ID, {(conn type), (rel id), (rel side)}, //Left side
- {(conn type), (rel id), (rel side)}, //Top side
- {(conn type), (rel id), (rel side)}, //Right side
- {(conn type), (rel id), (rel side)}, //Bottom side
Here, (conn type) is one of the connection types listed above, (rel id) is an identifier of the relative window or IDC_MAIN if you want to reference parent dialog, and (rel side) is the side of the relative window to which a connection is bound.
(conn type)是上表中列出的關聯方式的其中一種, (rel id)是相關窗口的一個標識或 IDC_MAIN, IDC_MAIN指定了子窗口與父窗口保持相關性,(rel side)是與相關窗口產生關聯的邊。
Each child window has four sides, so it has four connections—for left, top, right, and bottom. They are listed subsequently in the CResizer::CBorderInfo initialization above.
Let's consider the connection format (CResizer::CBorder structure) in more detail.
每個子窗口都有四個邊,因此它包含四個關聯邊--即左,上,右,下。在 CResizer::CBorderInfo中已經列出。讓我們看看這種結構 (CResizer::CBorder 結構體)的細節。
- {(conn type) , (rel id) , (rel side) }
- CResizer::eFixed CResizer::eLeft
- CResizer::eProportional IDC_MAIN CResizer::eTop
- {CResizer::eWidth , IDC_CTRL_ID , CResizer::eRight }
- CResizer::eHeight CResizer::eBottom
- CResizer::eXCenter
- CResizer::eYCenter
A fixed connection can bind the child window side not only to a side of the relative window, but also to its horizontal (CResizer::eXCenter) or vertical (CResizer::eYCenter) center line.
一個固定關聯值不僅可以被綁定到子窗口的邊,而且可以被應用到它的水平(CResizer::eXCenter)或垂直(CResizer::eYCenter)中心點。
A proportional connection needs only the width or height as relative window side. To specify width, use one of the horizontal sides (eLeft, eRight, or eXCenter); to specify height, use one of vertical sides (eTop, eBottom, or eYCenter).
一種連接屬性只需要寬度或高度作為相關窗口的邊。如果指定寬度,使用水平邊的一種就好(eLeft, eRight, 或eXCenter);如果要指定高度,使用垂直方向的一種就好 (eTop, eBottom, 或 eYCenter)。
Connections preserving width or height don't require relative window info. So, there can be any.
保留寬度和高度的關聯性不需要相關窗口信息。因此,啥都行。
Typical Usage
典型用法
- Make CResizer m_resizer a member variable of your dialog class.在你的對話框類中添加 CResizer m_resizer變量。
- Add the following code to OnInitDialog(), replacing the control IDs to your specific ones and adjusting connections as you wish (described above).添加以下代碼到你的 OnInitDialog()函數中,用你的ID替換數據結構體中的數據,用上面的方法調整你想要的關聯關系。
- static const CResizer::CBorderInfo s_bi[] = {
- {IDC_CTRL1, {CResizer::eFixed, IDC_MAIN, CResizer::eLeft}, //l
- {CResizer::eFixed, IDC_MAIN, CResizer::eTop}, //t
- {CResizer::eFixed, IDC_MAIN, CResizer::eRight}, //r
- {CResizer::eFixed, IDC_MAIN, CResizer::eBottom}},//b
- {IDC_CTRL2, {CResizer::eFixed, IDC_MAIN, CResizer::eLeft},
- {CResizer::eFixed, IDC_MAIN, CResizer::eBottom},
- {CResizer::eFixed, IDC_MAIN, CResizer::eRight},
- {CResizer::eFixed, IDC_MAIN, CResizer::eBottom}},
- };
- const nSize = sizeof(s_bi)/sizeof(s_bi[0]);
- m_resizer.Init(m_hWnd, NULL, s_bi, nSize);
- Add the following code to the OnSize() handler:添加以下代碼到OnSize()函數中。
- m_resizer.Move();
- Everything should work now.歐了
Some Final Tips(小提示)
- Resizer resizes controls in the order they are defined in the array, so (rel id) should always be defined (and, therefore, moved by the resizer) before it is used as relative window. Otherwise, resizer ASSERTs.
- Windows that are defined earlier in the array have higher priority. When windows have too small a size and child windows overlap, the window with lower priority is hidden.
- If you need to limit minimum or maximum window size, you can handle the WM_GETMINMAXINFO message.
小提示
- 這個類可以動態調整數組內的所有控件,因此 (rel id) 應該在它們被當作相對窗口使用之前就應該被定義(這樣才可以被resizer移動),否則就會報錯。
- 在數組中先被定義的窗口具有較高的優先級。當窗口太小并且定義中有窗口重貼情況,低優先級的窗口就會被隱藏。
- 如果你需要限制窗口最大和最小化尺寸,你需要處理 WM_GETMINMAXINFO消息.
參考鏈接:
https://blog.csdn.net/edger2heaven/article/details/45305705

浙公網安備 33010602011771號