Understand one of the principles of the MFC control bar window layout

Source: Internet
Author: User
I. Frame window

The Framework Window will receive the WM_SIZE message when its size is changed. The message processing function is CFrameWnd: OnSize. This function then calls RecalcLayout to relocate subwindows, its main code is as follows:

If (GetStyle () & FWS_SNAPTOBARS)
{
CRect rect (0, 0, 32767,327 67 );
RepositionBars (0, 0 xffff, AFX_IDW_PANE_FIRST, reposQuery, & rect, & rect, FALSE );
RepositionBars (0, 0 xffff, AFX_IDW_PANE_FIRST, reposExtra, & m_rectBorder, & rect, TRUE );
CalcWindowRect (& rect );
Setwindowpos (null, 0, 0, rect. Width (), rect. Height (), swp_noactivate | swp_nomove | swp_nozorder );
}
Else
{
Repositionbars (0, 0 xFFFF, afx_idw_pane_first, reposextra, & m_rectborder );
}

There are two small points to note: the first is the FWS_SNAPTOBARS style. Generally, the size of the frame window is automatically changed, and the Child window needs to be modified to adapt to the change of the frame window, but the FWS_SNAPTOBARS style is the opposite, it is used to adjust the size of the frame window to adapt to its sub-window, but I tracked it all the way and did not find any frame window with this style, they all take the else Branch (in fact, this style is prepared for CMiniDockFrameWnd, and the size of the Framework Window is determined by its internal control bar ); the second is to note that RecalcLayout is not reentrant. Although the MFC method to prevent reentrant is very simple and effective, however, its method cannot prevent the re-import of multiple threads. In other words, MFC itself is not a thread-safe Library.

Now we have entered the RepositionBars main function of the whole re-layout action, let's take a closer look at what it has done (this function has been documented in MSDN, and its meanings of several parameters are not described here):

First, it creates an AFX_SIZEPARENTPARAMS structure and fills in its member variables. The main two are bStretch and rect. The first one is a BOOL variable, indicates whether the Sub-window needs to be stretched (stretched to the same width or height as the customer area), and the last one is the current customer area size.

Then, the Framework Window sends wm_sizeparent messages to all its child windows in order of Z-order to notify them, calculate the size and location of the new customer based on the new customer zone, and deduct the rectangle occupied by the customer from afx_sizeparentparams: rect, in this way, after all the subwindows are calculated, the size of the remaining customer areas will be known in the Framework Window (PS: Who exactly sent the data? In what order? Take mdidemo as an example. In this example, a ctoolbar and a cthumbnaillistctrlbar are created, and the ID of the window sent under the tracking record is in the dock state, the values are 0xe801, 0xe81b, 0xe81e, 0xe81c, 0xe81d, view the definition of each sub-window ID. The order is the Dock bar on the left of the dock bar on the top of the Bar. Note that, the ID of the first child window is 0xe900 (0xe900 is defined as afx_idw_pane_first. In this example, it is the view window ID, and another ID corresponding to this ID is afx_idw_pane_last, the View window of SDI, The mdiclient window of MDI, And the ID of the separation bar window must be between the two IDs above), which is equal to nidleftover, so the wm_sizeparent message is not sent to it. Why can't tool bar and thumbnail bar receive messages? Because the Dock bar is its parent window, and the message is sent to the dock bar, the dock bar calculates the size of all the child windows it calls internally, so you don't need to worry about the frame window. In addition, the floating control bar does not accept the message wm_sizeparent. The reason is that the floating control bar does not change with the size of the main frame window ).

After the message is sent (here is the details. The Framework Window uses sendmessage to send the wm_sizeparent message, which means that only sendmessage is returned after the subwindow completes processing the message, the Framework Window will then send the message to the next subwindow. After all the subwindows are sent, it means that all the subwindows have been transferred from afx_sizeparentparams :: in the rect, remove the rectangle you want. The rest is the final available customer zone. Different return actions are executed based on the nflags value. Here, reposquery indicates that only query is performed, and the last remaining customer zone is copied to lprectparam without actual re-layout actions. If it is not reposquery, re-layout is required. For reposdefault, we need to adjust the size and position of the subwindow with the ID of nidleftover to the available customer zone after the subwindow is left by other subwindows, make this sub-window fully cover the last available area (that is to say, all sub-Windows crowded all customer areas ). When nflag is equal to reposextra, lprectparam is used to modify the remaining available areas before adjusting the size and position of the nidleftover subwindow. Specifically, afx_sizeparentparams is used :: the rect is scaled in and the shrinkage distance is specified by lprectparam, so that the last remaining customer zone is not filled by the nidleftover subwindow, but some places are empty. After the correction is completed, all the subwindows are re-arranged at the end.

Now, all the actions in the framework window are completed.

  Ii. Control the sub-Window

After analyzing the frame window, analyze the response actions of the control bar. Based on the previous tracing, we know that the control bar inherited from ccontrolbar, such as ctoolbar and cdialogbar, cannot receive the wm_sizeparent message except cstatusbar and cdockbar, their parent window cdockbar replaces them to receive the message. Therefore, the starting point of the re-layout process is cdockbar's function for processing wm_sizeparent messages cdockbar: onsizeparent (for cstatusbar, its starting point is ccontrolbar: onsizeparent, I am not planning to further analyze it here. If you are interested, you can do it yourself ). The first step is to analyze the operations performed by this function. This function is not long enough to list the complete code:

Lresult cdockbar: onsizeparent (wparam, lparam)
{
Afx_sizeparentparams * lplayout = (afx_sizeparentparams *) lparam;

// Set m_bLayoutQuery to TRUE if lpLayout-> hDWP = NULL
BOOL blyoutquery = m_blyoutquery;
CRect rectLayout = m_rectLayout;

M_blyoutquery = (lpLayout-> hDWP = NULL );
M_rectLayout = lpLayout-> rect;
LRESULT lResult = CControlBar: OnSizeParent (wParam, lParam );

// Restore m_blyoutquery
M_blyoutquery = blyoutquery;
M_rectLayout = rectLayout;

Return lResult;
}

As mentioned above, the WM_SIZEPARENT message transmits a pointer to an AFX_SIZEPARENTPARAMS struct as a parameter. Here we extract this struct and then determine whether AFX_SIZEPARENTPARAMS: hDWP is empty, yes, it means that the parent window only needs to be queried and does not really perform the re-layout action (return to RepositionBars. When nFlags is reposQuery, BeginDeferWindowPos is not called, so AFX_SIZEPARENTPARAMS :: hDWP must be NULL). After necessary Variable Protection, the OnSizeParent of the parent class CControlBar is entered. Here, the size of the control bar is determined based on the style of the control bar window, this is the case;

DWORD dwmode = lplayout-> bstretch? Lm_stretch: 0; // do you want to stretch it?
If (m_dwstyle & cbrs_size_dynamic) & m_dwstyle & cbrs_floating) // floating, variable shape
{
Dwmode | = lm_horz | lm_mruwidth; // common dimensions for calculating the horizontal state
}
Else if (dwstyle & cbrs_orient_horz) // horizontally docked
{
Dwmode | = lm_horz | lm_horzdock; // calculates the horizontal dock status size.
}
Else
{
Dwmode | = lm_vertdock; // calculates the vertical dock status size.
}
CSize size = CalcDynamicLayout (-1, dwMode );

It should be noted that CalcDynamicLayout is the last call. This function is a virtual function and CControlBar: CalcDynamicLayout is called first. This function calls CalcFixedLayout (also a virtual function ), we noticed that the CDockBar was overloaded, so after turning around, we went back to the CDockBar.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.