In the window client area of the program written in MFC, there may be several sub-windows (with WM_CHILD windows). The upper side is the toolbar, the middle is the view window, and the lower side is the status bar. Three windows are peaceful in peacetime in the client area of the framework, mutually overlap. The size of the main frame window changes, and other sub-windows can adjust their size in time to keep the mutual positional relationship. For example, the status strip window always remains at the bottom of the main frame client area, and its width is interested and the main frame customer. The region is consistent. The toolbar window always stops at a certain side of the primary frame, its width or height, and the width or height of the main frame client area, and the view window can always fill the remaining space of the main framework client area.
If we derive a window class from the CWND class and generate a window, you have to generate a number of sub-windows in its client area, we want these sub-windows to be arranged in the regulation, mutual overlap, when the size of the parent window changes When each sub-window can adjust its size and location in a timely, the positional size ratio between each sub-window is unchanged. When moving one or several sub-windows, other sub-windows can be grouped for this moving sub-window. Of course, we can use the function of managing the window in the API function to write your own management sub-window. However, if you have a toolbar, status bar, etc. in the client area of the parent window, can you get along with the sub-window you add to these MFCs? How do you guarantee that your child window does not cover the toolbar that can be parked around? When the toolbar and status are disappeared, your child window can know so that you can adjust your size to cover the space of the toolbar and the status bar. There is also a view in the client area based on the window of the document view architecture. Can you have a sub-window that you don't have to compete with the view window?
So you must understand the MFC window to manage the method of its client area. In fact, the method of the MFC window manages its client area is very simple: the parent window calls a function, and the sub-window responds to a message, it is so much.
CWnd :: Repositionbars function and wm_sizeparent message
Let's briefly describe the process of assigning a customer zone space for the child window: This process is completed with the parent window and the sub-window is completed. The parent window first provides an area in its client area called the start-up area. Then call a function, in this function, the parent window submits this area through a message to its first sub-window, the sub-window determines how big it is to take, and then it will occupy it in the available area Put out, so that the available area is cut off. The parent window then submits the remaining available area to the second sub-window through the same message, and the second child window cuts off according to its own needs. So this, each sub-window cuts it to a piece you need. The last remaining available area is used to the last sub-window. It can be seen that in addition to the last sub-window, the other sub-windows have their own algorithms in the message response function to determine how big it will occupy themselves in the available area, and the last child window is not necessarily selected, so it doesn't need this. Algorithm.
Of course, the initial available area is a rectangle, and each time the remaining available area is still a rectangle, it is impossible to be other shapes.
For example, in a typical single document program, the parent window is the main frame window derived from the cframewnd. The last child window is the view window. If you use the CSPLitterWnd to generate the zone, the last child window is the one of the separators. window. Other sub-windows are toolbar windows and status bars, as well as other control windows that may have.
In a typical multi-document interface program, the parent window is the main frame window. The last child window is overwritten in the main window client area, the background is black, has the window that contains the sub-frame window containing the document, which is a predefined window class. Window, its window class name is "mdiclient". If the CSPLitterWnd is used to generate the ingredients, the last child window is the window with the partition. Other windows is the toolbar window, status bar window, and other control windows that may have. This function and message are: Functions CWnd :: RepositionBars () and message WM_SIZEPART. This message is MFC custom, not Windows itself.
Let's briefly illustrate this function and message.
1. Function CWnd :: repositionbars ()
This function is not a virtual function, so you can't prepare your own version by overwriting in the derived class. You can only understand its function, so that you can use it flexibly.
Simply, the functionality of this function is to place the available client area information in the message parameter of the message WM_SIZEParent, then enumerate all the sub-windows of this window, give each sub-window (remove a specific sub-window, equivalent to The last sub-window mentioned above sends this message, and each sub-window that responds to this message will cut the available customer area. Finally, the size and position of the particular sub-window is adjusted to the available area just placed in the last remaining.
2. Message WM_SIZEPARENT
Each sub-window to participate in allocation client must respond to this message unless this sub-window is the specific sub-window.
The child window in response to this message should be done at least two things: 1, the available parent window client district will cut the piece you occupied. 2, according to the indication of the message parameters, adjust your size and position to the area that is just accommodated to the area you occupied or does not adjust.
Let's take a detailed introduction to the function cWnd :: repositionbars () and message WM_SIZEPARENT.
1. Function CWnd :: RepositionBars () void RepositionBars (UINT nIDFirst, UINT nIDLast, UINT nIDLeftOver, UINT nFlag = CWnd :: reposDefault, LPRECT lpRectParam = NULL, LPCRECT lpRectClient = NULL, BOOL bStretch = TRUE);
There are many parameters, but it is better to understand.
(1) Nidfirst and NIDLAST
Participate in the ID range of the sub-window to assign the parent window client area.
Each WM_CHILD style window has an ID, which is specified during the window creation. The sixth parameter of the function CWnd :: Create () is this ID. The parameters of the HMENU type in CREATEWINDOW and CREATEWINDOWEX, when there is WM_Child in the window, it does not finger the menu handle, but the ID of the window.
Nidfirst and NiDLAST parameters indicate: if the ID value of a sub-window is greater than or equal to Nidfirst and is less than or equal to NIDLAST, the WM_SIZEParent message will be sent to the sub-window in this function, which can participate in the assignment of the parent window client area.
(2) NIDLEFTOVER
As mentioned earlier, there is a specific sub-window that does not respond to the WM_SIZEParent message. Only when other sub-windows are allocated, it will come to pick the remaining in the Father Window Client area. Nidleftover is the ID of this sub-window. It must also be greater than or equal to NIDFIRST and less than or equal to NIDLAST.
(3) LPRECTCLIENT
This is a pointer to the RECT structure data. This RECT structure is stored in the initial availability area of the parent window client area. As each sub-window sends a WM_SIZEParent message in this function, each sub-window that responds to this message will cut the part you occupy. The last remaining part is the area where the ID of the ID is Nidleftover will occupy the area. This parameter can be NULL, and the initial available area is the entire parent window client area. (4) NFLAG and LPRECTPARAM
These two parameters are better than talking together. NFLAG is the functional flag of this function, which can have three values: ReposDefault, ReposQuery, and Reposextra.
When NFLAG is equal to ReposDefault, the function of the RepositionBars function is such that the ID is sequentially between Nidfirst and NIDLAST and does not equal the sub-window that does not equal to Nidleftover, and the sub-window responding to this message from LPRECTCLIENT. Cut the part you occupy and adjust your size and position to the size of the area you occupy, and finally the reositionsbars function also adjusts the size and location of the sub-window of NIDLEFTOVER to the size of the other child window. In the area, this sub-window is completely covered in the last available area. In this case, LPRECTPARAM can be NULL.
When nflag is equal to ReposQuery, the function of the RepositionBars function is such that the ID is sequentially between NidFirst and NIDLAST and does not equal the sub-window that does not equal to Nidleftover, and the sub-window that responds to this message from LPRECTCLIENT. Cut the part you occupy, but they don't adjust their size and position, and finally the Repositionbars function does not adjust the size and position of the child window of Nidleftover, but according to the value of Bstretch: If Bstretch is True, then copy the last remaining available area to the Rect structure pointed to the LPRECTPARAM; if bstretch is false, then the repositionbars function puts all other sub-windows from the high and wide (all sub-windows Tighten together, form a large rectangle, which makes it meaningful to copy to LPRECTPARAM's Bottom and Right members, and its top and left members are set zero. Using this nflag value to call repositionbars's purpose is not to rearrange the tiver window, but to see, if you replay the tiver window, these sub-windows will take up to one, and where is the last available area where is the location, etc. .
When NFLAG is equal to Reposextra, the functionality of the function is similar to the NFLAG equal to the reposdefault, and a little bit is a little bit. LPRECTPARAM needs to be used at this time. As mentioned earlier, when nflag is equal to ReposDefault, the RepositionBars function will adjust the size and position of the sub-window of NIDLEFTOVER to the scratched area of the sub-window, so that this sub-window is completely overridden in the last available area. . When NFLAG is equal to Reposextra, repositionbars is used to correct the last remaining available area before adjusting the size and location of the sub-window of Nidleftover. Suppose lprect points to the last available area, then this correction is made:
LPRECT-> TOP = LPRECTPARAM-> TOP;
LPRECT-> LEFT = LPRECTPARAM-> LEFT; LPRECT-> Right- = lprectParam-> Right;
LPRECT-> BOTTOM- = lpRECTPARAM-> BOTTOM;
Through this correction, the last remaining available area is not occupied by the child window of the ID Nidleftover, but is empty to leave some places to stay.
(5) Bstretch
This parameter has already mentioned a point in its role. It is mainly provided to each sub-window that responds to the WM_SIZEParent message, the sub-window such as the toolbar, the status bar, etc., when deciding how much it will be divided by the available space from the parent window client area, this parameter is also a basis for the judgment. See the toolbar and status bar response to WM_SIZEPARENT ().
2. Message WM_SIZEPARENT
This is an MFC custom message. In the TN024 in the MSDN, this news article is related to this message.
In the two parameters of the message, WPARAM is not used, and LParam is a pointer to an AFX_SIZEPARENTPARAMS structure variable, which is defined in the Repositionbars function:
AFX_SIZEPARENTPARAMS LAYOUT;
The AFX_SIZEPARENTPARAMS structure is defined as follows:
Struct Afx_SizeParentParams
{
HDWP HDWP;
RECT;
Size sizeetotal;
Bool bstretch;
}
The member of this structural variable is filled in in the Repositionbars function: its Bstretch member is the parameter Bstretch of Repositionbars, and the two members of its Sizetotal member are set to zero, its Rect member is from the parameter from the repositionbars LPRECTCLIENT The copy is coming, it is the initial availability area of the parent window customer area. Each sub-window that responds to this message must modify the value of the Rect member so that you can cut it.
What is the member HDWP? This has to know three API functions: BebindeferWindowPos (), DeferWindowPOS (), and EnddeferWindowPos (). These three API functions are used to batch the location and size of the window. BebindeferWindowPos () first informs Windows to assign a structure that will be used to store the location and size information, it is not a pointer to this structure, but returns the handle representing this structure, the type of handle is HDWP. Then each window that needs to be reset and the size is to call the deferWindowPos () function (this function requires the handle of the HDWP type as a parameter) to fill in the respective window location and size information. Finally, call EnddeferWindowPos () when an appropriate time, Windows will set the location and size of the relevant window according to the information in that structure. This method is fast compared to each window, which is set by SETWINDOWPOS (), this method is fast.
Ok, in the RepositionBars function is calling BebindeferWindowPos (), gets a handle of an HDWP type, which is filled in the member hdwp of the structural variable Layout on the above. The RepositionBars function then sends a WM_SIZEParent message to each eligible sub-window. In the sub-window in response to the WM_SIZEParent message, you want to call DEFERWINDOWPOS () to set the location and size information. When all the sub-windings respond to the WM_SIZEParent message, the RepositionBars function calls the EnddeferWindowPos () function, which in addition to the ID of the Nidleftover, all sub-windows have been ranked one time. As for the SizeTotal member of the structure, it accumulates the length and width dimensions of the available areas occupied by each sub-window. Each sub-window generally adds the high and width of the area you occupied to the CY and CX members of the Sizetotal structure, respectively. What does this mean? When the area occupied by each child window, this sizetotal structure is meaningful. The main frame window can make nflag equal to Reposquery, making Bstretch equal to false to call the Repositionbars function, the repositionbars function will put the SizetotAl structure A member value is copied to the LPRECTPARAM parameter to return to the main framework class (mentioned earlier), so that the main framework class knows how much space in its client area accounts. If your main frame window doesn't take advantage of this information, you can ignore Sizetotal members in response to the child window of the WM_SIZEParent message.
Id distribution
It can be seen that each sub-window has an ID, and the ID of the sub-window of the same parent window cannot be repeated. Some of the ready-made control sub-windows of MFC have a predefined ID:
ID Name ID value meaning
AFX_IDW_TOOLBAR 0XE800 / / The ID of the toolbar of the main window
AFX_IDW_STATUS_BAR 0XE801 / / ID ID
AFX_IDW_PREVIEW_BAR 0xE802 // PrintPreview Dialog Bar
AFX_IDW_RESIZE_BAR 0XE803 / / OLE IN-Place Resize Bar
AFX_IDW_REBAR 0XE804 // ComctL32 "Rebar" bar
AFX_IDW_DIALOGBAR 0XE805 / / CDIALOGBAR
There is also a view window of a single document program, the MDICLIENT window of multi-document programs, a separator window, and their ID value is between the two ID values:
AFX_IDW_PANE_FIRST 0XE900 / /
AFX_IDW_PANE_LAST 0XE9FF
You have to assign an ID for your own child window, don't repeat it. Generally, if you use the IDE menu view / resource symbols to join your ID, it will not be repeated. For ID, you can also look at the TN020 article in MSDN, which is a special ID.
Case Analysis
1. CFRAMEWND class How to call the repositionbars function
The previous parameters and meaning of the Repositionbars are introduced, and now see how the CFraMewnd class calls this function, and can learn the use of the repositionbars function.
CFRAMEWND class and its derived class-generated window can have a toolbar, status bar, and view window. When the size of the parent window changes, the respective positions and size ratios of these sub-windows remain unchanged, which requires the parent window to call the RepositionBars function once it changes its own size. The CFrameWnd class is centrally called repositionbars function in the function recalclayout. This class guarantees that the function recalcLayout is called when the window size changes, so that the repositionbars function can be called timely, ensuring that each sub-window can adjust their position and size in time. RecalcLayout is a virtual function. The functionality of this function is to provide an initial availability area within the client area of the main frame, and put this area in a CRECT type variable. This function is roughly like this:
Void CFrameWnd :: RecalcLayout (Bool Bnotify)
{
IF (m_binRecalcLayout)
Return; // This is probably to prevent the function from re-entry
m_binRecalcLayout = true;
....
....
....
....
IF (getStyle () & fws_snaptobars
{
CRECT RECT (0, 0, 32767, 32767);
RepositionBars (0, 0xfff, AFX_IDW_PANE_First, Reposquery,
& Rect, & Rect, False;
RepositionBars (0, 0xfff, AFX_IDW_PANE_First, Reposextra,
& m_RectBorder, & Rect, True;
CalcwindowRect (& Re);
Setwindowpos (NULL, 0, 0, Rect.width (), Rect.height (),
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
}
Else
Repositionbars (0, 0xff, AFX_IDW_PANE_FIRST, RepOSEXTRA, & M_RECTBORDER);
m_binRecalcLayout = false;
} It can be seen that MFC thinks that this function cannot be re-entered. It is also possible to prevent re-entry in the preparation of its own recalclayout () function.
The following IF statement checks if the frame window has a style fWS_SNAPTOBARS, when is this style? I think so: usually changed in the size of the main frame window
When the child window adjusts its size to keep up with the size of the frame window when responding to the WM_SIZEParent message. There is such a situation: the number of sub-windows in the client area of the parent window is dynamic
Include, and these sub-windings cannot overlap each other, their size is not good for some reason. Then when the number of sub-windings is increased, if you do not adjust the parent window's own size, it will guide
There is no extra spatial arrangement for a blank or newly added sub-window to leave a blank or newly added. FWS_SNAPTOBARS style is in this case, allowing the parent window to adjust its size to hold the child window.
Look at the statement in this branch, it seems like this.
There is generally no FWS_SNAPTOBARS style, so it is generally implemented in the ELSE branch. Simply call repositionbars to rearrange all sub-windows in this branch, its parameters
LPRECTCLIENT uses the default null value, meaning the initial available area is the entire client area of the parent window.
You can write your own RecalcLayout function in your own derived class to call the RepositionBars function with your own method. Note that the window of the CFrameWnd class is just created
The recalclayout function is also called. At this time, some users you may add have not yet been created, so if you want to quote your own handles yourself, you must use: IsWindow ( The function determines whether the window handle is available. Otherwise, illegal operation will occur.
Actual exercise
Due to limited energy, only a practical example: the view, toolbar and status bar rushed to the right
We have to generate this interface: view window, toolbar and status have been in the right, and the left is a window you add.
The first step: Start AppWizard Generate a single document program, all of which use the default settings.
Step 2: Add a member CWnd M_MyWnd in the CMAINFRAME class.
Step 3: Add these lines in the cmainframe :: oncreate () function:
m_mywnd.createex
(
WS_EX_CLIENTEDGE,
AfxRegisterWndClass
(
CS_HREDRAW | CS_VREDRAW,
:: LoadCursor (Null, Idc_Arrow),
:: CreateSolidbrush (RGB (190, 190, 190))
),
""
WS_Visible | WS_CHILD,
CRECT (0, 0, 0, 0),
this,
IDC_MYPANE // uses IDE's menu View / Resource Symbols Item Added ID.
);
Step 4: Start ClassView, plus virtual function recalclayout (), and the function body is written in CMAINFRAME:
Void CMAINFRAME :: RECALCLAYOUT (BOOL BNOTIFY)
{
IF (m_binRecalcLayout)
Return;
m_binRecalcLayout = true;
// Rect1 is the area that will occupy the new window
// RECT2 is provided to the initial available area of the toolbar, status bar, and view window.
CRECT RECT1, RECT2;
GetClientRect (& Rect1);
RECT1.Right = Rect1.right / 3;
GetClientRect (& Rect2);
Rect2.Left = Rect2.right / 3;
IF (: iswindow (m_mywnd.m_hwnd) // This sentence is not less
m_mywnd.moveWindow (& Rect1);
Repositionbars (0, 0xfff, AFX_IDW_PANE_FIRST, RepOSEXTRA, CRECT (0, 0, 0), & Rect2);
m_binRecalcLayout = false;
}
Step 5: Add an ID: IDC_Mypane with the IDE menu View / Resource Symbols item.
Step 6: Compile and run the program.
Ok, there is a gray window on the left side of the main frame window, which accounts for one-third of the main window customer area. The toolbar, status bars, and views have been rushed to two-thirds of the right side.