Detailed analysis and examples of MFC Window Location Management

Source: Internet
Author: User
It is usually written in MFC Program There may be several subwindows (Windows with wm_child style) in the client area ). The top is the toolbar, the middle is the View window, and the bottom is the status bar. The three windows coexist in the customer area of the framework and do not overlap with each other. The size of the main frame window has changed. Other subwindows can adjust their size in time to keep their positions unchanged. For example, the status bar window can always be at the bottom of the main frame client area, and its width is always the same as that of the main frame customer zone. The toolbar window can always be docked on one side of the main frame, and its width or height can always be the same as the width or height of the main frame customer area. The View window can always fill the remaining space in the main frame customer area.

If we derive a window class from the cwnd class and generate a window, several subwindows will be generated in its customer area. We want to make these subwindows arranged in a regular and non-overlapping manner, when the size of the parent window changes, the size and position of each child window can be adjusted in a timely manner, so that the proportional relationship between the positions and sizes of each child window remains unchanged. When one or several subwindows are moved, other subwindows can give up their positions in time. Of course, we can use the Management window function in API functions to compile our own method for managing subwindows. However, if you have a toolbar, Status Bar, and other subwindows in the parent window, can the subwindows you added work well with the subwindows provided by the MFC? How do you ensure that your subwindow does not overwrite the toolbar that can be docked everywhere? How can you know when the toolbar and status bar disappear, so that you can adjust your size in time to overwrite the space occupied by the toolbar and status bar? There is also a view in the customer zone of the window based on the document view framework. Can the child windows that you add hard on your own compete with the View window?

Therefore, you must understand the methods for managing the customer zone of the MFC window. In fact, the method for managing the client zone of the MFC window is very simple: the parent window calls a function, and the subwindow responds to a message, so much.

Cwnd: repositionbars function and wm_sizeparent message

First, let's briefly describe the process of allocating the customer space for the Child window in the MFC window: this process is completed by the parent window and the Child Window. The parent window first provides a region in the customer zone, which is called the start zone. Then, call a function. In this function, the parent window submits this area to the first subwindow through a message. The subwindow determines the size of the subwindow that you want to occupy, then, you can drag out the occupied part in the available area so that the available area is split. The parent window then submits the remaining available areas to the second child window through the same message, and the second child window switches out one piece as needed. In this way, each sub-window is split into one that you need. The remaining zones are used in the last sub-window. It can be seen that except the last sub-window, other sub-windows must have their own in the message response function.AlgorithmTo determine the size of the available area. the last sub-window does not need such an algorithm because it has no choice.

Of course, the initial available area is a rectangle, and the remaining available area after each cut is still a rectangle, which cannot be in other shapes.

For example, in a typical single-document program, the parent window is the main frame window derived from cframewnd, And the last sub-window is the View window. If csplitterwnd is used to generate separation bars, the last sub-window is the window with separators. Other subwindows are toolbar windows, status bar windows, and other control windows.

In a typical multi-Document Interface Program, the parent window is the main frame window, And the last child window is the window that covers the main window client area. The background is black-gray and has the child frame window containing the document, this is a window with a predefined window class. Its window class name is "mdiclient ". If csplitterwnd is used to generate a separator, the last subwindow is the one with the separator. Other windows are toolbar windows, status bar windows, and other control windows.

The function and message are: cwnd: repositionbars () and wm_sizeparent. This message is customized by MFC, not by windows.

This function and message are briefly described.

1. Function cwnd: repositionbars ()

This function is not a virtual function, so you cannot compile your own version by overwriting In the derived class. You can only understand its functions for flexible use.

To put it simply, this function places the available customer zone information in the message parameters of the message wm_sizeparent, and then enumerate all the subwindows in this window, send this message to each subwindow (removing a specific subwindow is equivalent to the last subwindow mentioned above, each subwindow that responds to this message will split the available customer zones. At last, adjust the size and position of the specific sub-window to the available area at the end.

2. Message wm_sizeparent

Each subwindow to participate in the distribution of customer areas must respond to this message, unless this subwindow is the specific subwindow.

There are at least two things to do in the subwindow to respond to this message: 1. Switch the available parent window customer partition to the one occupied by the customer. 2. According to the Message Parameter instructions, adjust the size and position of the message to fit in the area occupied by the message or do not adjust it.

The following describes in detail the function cwnd: repositionbars () and message wm_sizeparent.

1. Function cwnd: repositionbars () void repositionbars (uint nidfirst, uint nidlast, uint second, uint nflag = cwnd: reposdefault, lprect second = NULL, lpcrect lprectclient = NULL, bool bstretch = true );

There are many parameters, but they are quite understandable.

(1) nidfirst and nidlast

The ID range of the subwindow that participates in allocating the parent window customer area.

Each wm_child window has an ID, which is specified during window creation. The sixth parameter of the function cwnd: Create () is the ID. The hmenu type parameter in the createwindow and createwindow Wex functions. When the window style contains wm_child, it is not the menu handle, but the ID of the window.

The nidfirst and nidlast parameters indicate that, if the id value of a subwindow is greater than or equal to nidfirst and less than or equal to nidlast, wm_sizeparent messages will be sent to this subwindow in this function, this subwindow can be used to allocate the customer area in the parent window.

(2) nidleftover

As mentioned above, there is a specific subwindow that does not respond to the wm_sizeparent message. Only when other sub-windows are allocated is used up will the remaining sub-windows in the parent window be retrieved. Nidleftover is the ID of this subwindow. It must 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 stores the initial available areas of the parent window customer zone. As the function sends the wm_sizeparent message to each subwindow in sequence, each subwindow that responds to the message will remove the portion occupied by it. The last part is the area that the subwindow with ID nidleftover will occupy. This parameter can be null, and the initial zone is the entire parent window customer zone.

(4) nflag and lprectparam

It is better to put these two parameters together. Nflag is the Function Identifier of the function. It can have three values: reposdefault, reposquery, and reposextra.

When nflag is equal to reposdefault, The repositionbars function sends wm_sizeparent messages to subwindows whose IDs are between nidfirst and nidlast and are not equal to nidleftover, each subwindow that responds to the Message removes the part occupied by it from the structure indicated by lprectclient, and adjusts its size and position to the size of the region occupied by it, finally, the repositionbars function also adjusts the size and position of the subwindow whose ID is nidleftover to the available area left by other subwindows, so that the subwindow completely overwrites the last available area. In this case, lprectparam is not required. It can be null.

When nflag is equal to reposquery, The repositionbars function sends wm_sizeparent messages to subwindows whose IDs are between nidfirst and nidlast and are not equal to nidleftover, each subwindow that responds to this message is segmented from the structure indicated by lprectclient, but they do not adjust their size and position, finally, the repositionbars function does not adjust the size and position of the subwindow whose ID is nidleftover. Instead, it performs an action based on the bstretch value. If bstretch is true, the repositionbars function copies the last available regions to the rect structure pointed to by lprectparam. If bstretch is false, then the repositionbars function puts the height and width of the available areas occupied by all other sub-Windows (this value makes sense only when all sub-windows are tightly arranged to form a large rectangle) copy to lprectp In the bottom and right members of the rect structure directed by Aram, the top and left members are set to zero. The purpose of calling repositionbars with this nflag value is not to rearrange subwindows, but to see how many subwindows will occupy if subwindows are rearranged, the location of the last available area and so on.

When nflag is equal to reposextra, the function is similar to nflag when it is equal to reposdefault. In this case, lprectparam is used. As mentioned above, when nflag is equal to reposdefault, The repositionbars function will adjust the size and position of the subwindow with the ID of nidleftover to the available area left by other subwindows, make this sub-window completely overwrite the last available area. When nflag is equal to reposextra, before adjusting the size and position of the subwindow whose ID is nidleftover, repositionbars also uses lprectparam to correct the remaining available areas. If lprect points to the final zone, the correction is as follows:

Lprect-> top + = lprectparam-> top;
Lprect-> left + = lprectparam-> left;
Lprect-> right-= lprectparam-> right;
Lprect-> bottom-= lprectparam-> bottom;

With this correction, we can leave the remaining available areas empty for use instead of the sub-windows with the ID of nidleftover.
(5) bstretch

The role of this parameter has been mentioned above. It is mainly provided for subwindows that respond to wm_sizeparent messages. when determining the number of subwindows, such as the toolbar and status bar, you can determine how much space you want to move from the free space in the customer zone of the parent window, this parameter is also a basis for judgment. For details, see the onsizeparent function of the toolbar and status bar responding to wm_sizeparent ().

2. Message wm_sizeparent

This is an MFC custom message. Tn024 Technology in msdnArticleMessage description.

Wparam is not used in the two parameters of the message. lparam is a pointer to an afx_sizeparentparams structure variable, which is defined in the repositionbars function:

Afx_sizeparentparams layout;

The structure of afx_sizeparentparams is defined as follows:

struct afx_sizeparentparams
{< br> hdwp;
rect;
size sizetotal;
bool bstretch;
};
the member of this structure variable is filled in the repositionbars function: Its bstretch member is the repositionbars parameter bstretch, both CX and Cy members of sizetotal are set to zero, and their rect members are copied from the lprectclient parameter of repositionbars, it is the initial available area of the parent window customer zone. Each subwindow that responds to the message must modify the value of the rect member so that the part occupied by the subwindow can be removed.
what is hdwp? We need to know three API functions: bebindeferwindowpos (), deferwindowpos (), and enddeferwindowpos (). These three API functions are used to set the window position and size in batches. Bebindeferwindowpos () first notifies windows to allocate a structure that will store the location and size information of the window. Instead of returning a pointer to the structure, bebindeferwindowpos () returns a handle representing the structure, the type of the handle is hdwp. Then, the deferwindowpos () function is called for every window that needs to reset its position and size (the hdwp type handle is required for this function ), in this way, you can enter the location and size of the window in that structure. Finally, call enddeferwindowpos () at an appropriate time, and Windows will set the location and size of the window according to the information in the structure. This method is faster than setting one by one using setwindowpos () and other functions for each window.

Well, in the repositionbars function, bebindeferwindowpos () is called to obtain an hdwp type handle, which is filled in to the hdwp Member of the preceding Structure Variable layout. Then, the repositionbars function sends the wm_sizeparent message to each qualified sub-window. In each subwindow that responds to the wm_sizeparent message, call deferwindowpos () to set the position and size information. After all the sub-windows have responded to the wm_sizeparent message, the repositionbars function calls the enddeferwindowpos () function. In this way, except for the sub-Windows whose ID is nidleftover, all the sub-windows are arranged at one time.

As for the significance of the sizetotal Member of the structure, it accumulates the length, width, and size of the available area occupied by each sub-window. When each sub-window responds to the wm_sizeparent message, it is generally necessary to accumulate the height and width of the region it occupies into the Cy and cx members of the sizetotal structure respectively. What is the significance of this? This sizetotal structure makes sense when the areas occupied by each subwindow are merged. The main frame window can make nflag equal to reposquery and bstretch equal to false to call the repositionbars function, the repositionbars function copies the two member values of the sizetotal structure to the lprectparam parameter and returns them to the main framework class (as mentioned earlier ), in this way, the main framework class will know how much space its subwindows occupy in the customer zone. If your main Framework Window does not use this information, then the subwindow responding to the wm_sizeparent message can ignore the sizetotal member.

Id allocation

As you can see, each subwindow has an ID. the IDs of subwindows in the same parent window cannot be the same. Some ready-made control subwindows of MFC have predefined IDs:

ID name ID value meaning

Afx_idw_toolbar 0xe800 // The toolbar ID of the Main Window
Afx_idw_status_bar 0xe801 // ID of the status bar
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 like a single-document program, the mdiclient window of Multi-document programs, and a separation window. Their ID values are between the following two ID values:
Afx_idw_pane_first 0xe900 //
Afx_idw_pane_last 0xe9ff

If you want to assign an ID to your child window, do not repeat the above. Generally, if you use the IDE menu view/resource symbols item to add your own ID, it will not be repeated. For the ID, you can also refer to the tn020 article in msdn, which is dedicated to ID.

Instance analysis

1. How does the cframewnd class call the repositionbars function?

We have introduced the parameters and meanings of repositionbars. Now let's take a look at how the cframewnd class calls this function and learn how to use the repositionbars function.

The cframewnd class and its derived classes can generate window sub-windows such as the toolbar, Status Bar, and View window. When the size of the parent window changes, the positions and proportions of these subwindows remain unchanged, this requires the parent window to call the repositionbars function once its size changes. The cframewnd class calls the repositionbars function in the recalclayout function. This class ensures that the function recalclayout is called when the window size changes, so that the repositionbars function can also be called in a timely manner, ensuring that each subwindow can adjust its position and size in a timely manner.

Recalclayout is a virtual function. This function provides an initial available zone in the customer zone of the main framework and stores this zone in a variable of the crect type. This function is roughly like this:

Void cframewnd: recalclayout (bool bnotify)
{
If (m_binrecalclayout)
Return; // This is probably preventing the function from being reimported.
M_binrecalclayout = true;
....
....
....
....
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 );
M_binrecalclayout = false;
} We can see that MFC does not think this function can be reinjected. The same method is also used to prevent re-entry when compiling your own recalclayout () function.
The IF statement below checks whether the framework window has the fws_snaptobars style. When will this style be used? I think so: Usually the size changes in the main frame window.
When the child window responds to the wm_sizeparent message, adjust its size to keep up with the size change of the frame window. In this case, the number of child windows in the customer zone of the parent window changes dynamically.
And these sub-Windows cannot overlap, and their sizes cannot be changed for some reason. When the number of child windows is increased or decreased, if the size of the parent window is not adjusted
Leave blank space in the customer area or there is no extra space for the Newly Added Sub-window. The fws_snaptobars style is used in this case, so that the parent window can be adjusted to accommodate the child window.
The statement in this branch seems to be like this.
Generally, there is no fws_snaptobars style. Therefore, else branches are generally executed. In this branch, repositionbars is called to rearrange all subwindows. Its Parameters
Lprectclient uses the default null value, which means that the initial zone is the entire customer zone of the parent window.
You can write your own recalclayout function in your own derived class to call the repositionbars function in your own way. Note that the cframewnd class has just been created.
The recalclayout function is also called. At this time, some users may not have created their own child windows. Therefore, if you want to reference the handle of a user's own child window in this function
Use the: iswindow () function to check whether the window handle is available. Otherwise, the operation is invalid.

Practical drills
Due to limited energy, only one practical example is provided: the view, toolbar, and status bar are pushed to the right.
We need to generate a View window. The toolbar and status bar are all on the right, and the left side is a self-added window.
Step 1: Start Appwizard to generate a single-document program. Use the default settings.
Step 2: Add a member cwnd m_mywnd to the cmainframe class.
Step 3: Add the following lines to 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 ),
This,
Idc_mypane // ID added by using the IDE menu view/resource symbols item.
);

Step 4: Start classview and add the virtual function recalclayout () to the cmainframe. Write the function body as follows:
Void cmainframe: recalclayout (bool bnotify)
{
If (m_binrecalclayout)
Return;
M_binrecalclayout = true;

// Rect1 is the area occupied by the newly added window
// Rect2 is 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 cannot be less
M_mywnd.movewindow (& rect1 );
Repositionbars (0, 0 xFFFF, afx_idw_pane_first, reposextra, crect (0, 0, 0), & rect2 );
M_binrecalclayout = false;
}

Step 5: Use the IDE menu view/resource symbols to add an ID: idc_mypane.
Step 6: Compile and run the program.

Well, there is a gray window on the left of the main frame window, which accounts for 1/3 of the customer area of the main window. In the toolbar, the status bar and view are all pushed to 2/3 on the right.

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.