CResizableFormView






3.50/5 (27 votes)
Nov 29, 2000

191728

2548
Extension of Paolo Messina's CResizableDialog concept
Introduction
The inspiration for this coding project was the result of a) Paolo Messina's
article on his CResizableDialog code, and b)
me mentioning I had adapted a CFormView
to use a
CResizablePage
in an embedded property sheet.
The CResizablePage
in a formview was a minor exercise compared
to this. What I've come up with is a CResizableFormView
. This code
is based entirely on Paolo's CResizableDialog
code.
If you're not interested in how I did it, Skip to the bottom of this article to see how to implement it yourself.
The Concept
It seemed to me that if a dialog box could benefit from this technique, then so could a formview, because after all, a formview is nothing more than a view that acts like a dialog box. It even uses a resource template like a dialog box.Initially
The initial coding was fairly straightforward. I created a CFormView-derived class calledCResizableFormView
. Next, I copied
all of the utility functions (functions not contributed by ClassWizard). Then, I
evaluated the need/availability of some of the windows messages Paolo's code was
using. I ended up only needing to handle the WM_SIZE
command.
Lastly, I decided that the min/max window size code was not applicable to a
formview, so I deleted the code involving that particular aspect of
CResizableDialog
.
Implementation
After getting the code to compile, I tried deriving a new class based on my newCResizableFormView
. After some
experimentation, I discovered that I could not use the AddAnchor
function until AFTER the InitialUpdate
had completed. If I didn't
follow this rule, the controls would not resize correctly. void CFormview2View::OnInitialUpdate() { CResizableFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); ResizeParentToFit(); // put our code AFTER the stuff ClassWizard gave us. AddAnchor(IDC_LIST1, TOP_LEFT, BOTTOM_RIGHT); AddAnchor(IDC_GROUP1, TOP_LEFT, BOTTOM_LEFT); }
Minor Issues
After playing around with resizing for a while, I discovered that if I made the view window smaller than the original dialog template, a couple of bad things happened involving the controls that were "anchored".- The listbox disappeared altogether and would only partially appear as I made the view horizontally larger.
- The groupbox around the radio controls would just keep resizing until nothing was left (of the groupbox).
It was obvious at that point that I had to include some code to restrict the
controls from resizing once they reached (or were smaller than) their original
size. I also assumed that I had to be mindful of getting the correct original
size, meaning I had to determine each control's size before the window was
allowed to be resized the first time. Assuming that the programmer could decide
to do something other than use a call to MFC's ResizeParentToFit
, I
had to make sure to get the control's info immediately after the view was
created, but before it was resized. I wanted to impact as little of Paolo's
original code as I could manage, so the fix was a while coming.
To remedy the situation, I created a CTypedPtrArray
that held a
new structure. This structure contains the original size and location of each
"anchored" control, as well as its HWND
and control ID. To support
the structure, I had to also write a couple of new functions. Here are the
details:
void CResizableFormView::AddResizedControls()
This function is responsible for determining the HWND
and window
size / location of the specified control, as well as storing its anchor
positions. The parameter list is identical to the original
AddAnchor
function. Once all of this information was gathered, the
control was added to the new CTypedPtrArray
for safe-keeping.
void CResizableFormView::AnchorControls()
This function actually calls AddAnchor
for all of the controls
the programmer specified when he/she called the AddResizedControls
function. The significance of this will be evident later.
Results
In order to implement the sizing/positioning fix, A new order of execution was required in theCResizableFormView
-derived class. The
OnInitialUpdate
function now looks like this: void CFormview2View::OnInitialUpdate() { // jms - 11/28/00 - new code starts // We do this here because we need to get the *original* size of the // controls *before* the dialog is sized the first time. I don't know // what will happen if we do it after, but I didn't want to find out. // // Since we do this here, I decided to pass the parameters needed by // the AddAnchor() function to eliminate the need to call AddAnchor // from this function (after the view had been resized). AddResizedControl(IDC_LIST1, TOP_LEFT, BOTTOM_RIGHT); AddResizedControl(IDC_GROUP1, TOP_LEFT, BOTTOM_LEFT); // jms - 11/28/00 - new code stops CResizableFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); ResizeParentToFit(); // Normally, we would put the calls to AddAnchor AFTER we call // ResizeParentToFit(). //AddAnchor(IDC_LIST1, TOP_LEFT, BOTTOM_RIGHT); //AddAnchor(IDC_GROUP1, TOP_LEFT, BOTTOM_LEFT); // jms - 11/28/00 - new code starts // Now anchor the controls we specified earlier in this function. We call // this function because it cycles thru the list of controls that are to // be resized. This prevents us from having to call AddAnchor (lots of // redundant typing at this point). AnchorControls(); }
But what if you wanted the view to NOT resize itself according to the dialog
template. That's easy. Just calculate the size of the parent window of the
formview, and call MoveWindow
before exiting
OnInitialUpdate
. Here's an example:
void CFormview2View::OnInitialUpdate() { AddResizedControl(IDC_LIST1, TOP_LEFT, BOTTOM_RIGHT); AddResizedControl(IDC_GROUP1, TOP_LEFT, BOTTOM_LEFT); AddResizedControl(IDC_IPADDRESS1, BOTTOM_RIGHT); CResizableFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); // Here's where the difference lies. We don't want to call ResizeParentToFit() until // AFTER we calculate the true (initial) size of the parent frame. CRect rectFrame; CFrameWnd* pFrame = GetParentFrame(); ASSERT_VALID(pFrame); pFrame->GetWindowRect(rectFrame); CSize size = rectFrame.Size(); // Now, we can call ResizeParentToFit() and anchor the controls. ResizeParentToFit(FALSE); AnchorControls(); // Finally, we need to actually resize the frame to its original dimensions. This // allows the anchor code to work with its existing code. pFrame->MoveWindow(rectFrame, TRUE); }
The Final Word
To implement the CResizableFormView
, perform the following
steps:
- Create a
CFormView
class and its dialog template if necessary. - Change the base class of your
CFormView
-derived class toCResizableFormView
. - #include "ResizableFormView.h" in your derived formview's header file.
- If the function isn't already there, use ClassWizard to override the
OnInitialUpdate
function. - Call
AddResizedControls
for each control that will be resized/repositioned. Do this BEFORE the call to the base class'OnInitialUpdate
. - Call
AnchorControls
. Do this AFTER the call toResizeParentToFit