Click here to Skip to main content
Click here to Skip to main content

CResizableFormView

By , 6 Jun 2001
 

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 called CResizableFormView. 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 new CResizableFormView. 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 the CResizableFormView-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:

  1. Create a CFormView class and its dialog template if necessary.
  2. Change the base class of your CFormView-derived class to CResizableFormView.
  3. #include "ResizableFormView.h" in your derived formview's header file.
  4. If the function isn't already there, use ClassWizard to override the OnInitialUpdate function.
  5. Call AddResizedControls for each control that will be resized/repositioned. Do this BEFORE the call to the base class' OnInitialUpdate.
  6. Call AnchorControls. Do this AFTER the call to ResizeParentToFit

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

John Simmons / outlaw programmer
Software Developer (Senior)
United States United States
Member
I've been paid as a programmer since 1982 with experience in Pascal, and C++ (both self-taught), and began writing Windows programs in 1991 using Visual C++ and MFC. In the 2nd half of 2007, I started writing C# Windows Forms and ASP.Net applications, and have since done WPF, Silverlight, WCF, web services, and Windows services.
 
My weakest point is that my moments of clarity are too brief to hold a meaningful conversation that requires more than 30 seconds to complete. Thankfully, grunts of agreement are all that is required to conduct most discussions without committing to any particular belief system.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionI want to fit the dialog in form??memberjohnthecoder25 Aug '08 - 19:50 
hi,
Now I am using CResizableFormview class in my own project.I need to set the main window size to 770*570.When I set this as the main window size.Then scrollbars appeared.I dont want this scrollbars.I just want to fit the dialog with in the main window.How can i do that?
Please help........
 
regards,
john...
QuestionMaximized MDI window problemmembersdr27 Jun '06 - 4:10 
Hi.
 
I'm using your class and it works fine. Today I found problem which I don't know how to handle...
 
I have an MDI application in which, at start, one CResizableFormView is maximized to fit whole place for MDI child windows. Then, closing this window and reopening causes all anchored controls not to be placed properly(like they weren't ever anchored). All CResizableFormView initialization and anchoring controls is done properly (checked while debugging). What can cause this problem?
 
I initialize anchoring controls in order:
AddResizedControl(xxx,...,...);
CResizableFormView::OnInitialUpdate();
AnchorControls();
 
Anyone has any ideas?
Any help appreciated...
 
sdr
GeneralMissing .dsp file to open the project!memberPerryz4 Dec '04 - 17:25 
Please check that.
GeneralRe: Missing .dsp file to open the project!memberbatsword10 Sep '10 - 21:08 
can not find it D'Oh! | :doh:
Questionnot resizing?memberlagonz4 May '04 - 16:45 
First of all, thanks for the class it's a life saver!!!!
 
I am using the class, but when I start my app it doesn't respond to the resizing of the main window.
 
I had to add the function "AnchorControls()" in the method for the WM_SIZE message. Then the controls respond to the sizing, however, it doesn't enlarge the component but just moves them according to their anchor.
 
Also, the method "ResizeParentToFit()" only adjust the main window to the form if "FALSE" is passed as parameter, weird, but I can live with that.
 
HelpConfused | :confused:
AnswerRe: not resizing?memberlagonz4 May '04 - 16:52 
OK, I see why it wasn't responding to the resizing of the main window. Somehow, because I wasn't overriding the OnSize method it was calling CFormView::OnSize D'Oh! | :doh: , when overriding, the call to OnSize is changed to CResizableFormView::OnSize, this is the method that contains the repositioning of the control.
Poke tongue | ;-P
 
I still have the remaining problem of the controls not getting resized, they are just getting moved according to their anchors. Is there a flag I have to set in the control's properties to get them resized?
 
Help Confused | :confused:
 
AWESOME CLASS!!!
GeneralGot an Error!!member*Dreamz16 Apr '04 - 3:24 

AddAnchor(UINT ctrl_ID .. doesn't work for me.So i am using
AddAnchor(HWND wnd,...
When i am resizing the window it is showing error at ResizableFormView.cpp.
void CResizableFormView::ArrangeLayout()
{
FORMCONTROL* pCtrl = GetFormControl(pl->hwnd);
--> //Failing at GetFormControl,getting null.
-->newrc.left = max(newrc.left, pCtrl->rect.left);
 
I am using one Tree control and Web browser control in the dialog.
 
Can anybody help me.. Smile | :)
 
Thanks
GeneralBad Dialog Templatememberniallmack4 Nov '03 - 12:19 
I tried to get the formview working in my CSplitterView, but it says bad dialog template. I added a simple dialog with just a static text as a sanity check, and followed the instructions you put to incorporate it into my project then I got this error in formview.cpp and haven't been able to figure it out.
 
// dialog template must exist and be invisible with WS_CHILD set
if (!_AfxCheckDialogTemplate(m_lpszTemplateName, TRUE))
{
---> ASSERT(FALSE); // invalid dialog template name <-----
PostNcDestroy(); // cleanup if Create fails too soon
return FALSE;
}
 
Thanks for your time
 
Niall

GeneralRe: Bad Dialog Templatemember*Dreamz16 Apr '04 - 3:09 

Set the Window style in the Dialog properties to Child and Border None.
I have set no other properties also. Smile | :)
GeneralBug and Solution - Resizing-problemmemberSiegmund Frenzel7 Aug '03 - 22:05 
Hello,
 
please try the following:
Open the Demo-Application. Make it small enough, that you can see scrollbars.
Now scroll to the right and bottom.
Now make the app (for example one pixel) bigger. The controls were drawed at the wrong places.
 
The problem is that GetClientRect returns the Size of the visible area. If you have scrolled to the right bottom the coordinates (0,0) of the area are "somewhere" on the original form. In "AddAnchor" you remember the margins between the Border of the View and the control. After scrolling and resizing the controls are positioned x/y pixels from (0,0) which is not the left top border of the View but of the visible area.
 
You have to call GetTotalSize() to retrieve the total size of the frame (not the visible one)
 
In "ArrangeLayout" you have to calculate which is bigger: the actual size or the total size and use that value for calculating. Do not use the initial size. ==> If you have a very small frame, the created view is mostly smaller than the original Formview. (The frame has initial scrollbars)
 
At the end you have to take the offset into account: The area from the (0,0)-coordinates from the whole view to the (0,0)-coordinates of the visible area.
When you have calculated where a control should be positioned you have to subtrate the difference between the two (0,0) Points.
 
Enough talked nonsense. Here is the code:

void CResizableFormView::AddAnchor(HWND wnd, CSize tl_type, CSize br_type)
{
...
...
...
CSize tl_margin, br_margin;
 
if (br_type == NOANCHOR)
{
br_type = tl_type;
}
 
//Da wird eine Scrollview haben, die maximale Größe nehmen
CSize TotalSize = GetTotalSize ();
 
// calculate margin for the top-left corner
tl_margin.cx = objrc.left - TotalSize.cx * tl_type.cx / 100;
tl_margin.cy = objrc.top - TotalSize.cy * tl_type.cy / 100;

// calculate margin for the bottom-right corner
br_margin.cx = objrc.right - TotalSize.cx * br_type.cx / 100;
br_margin.cy = objrc.bottom - TotalSize.cy * br_type.cy / 100;
 
// add to the list
m_plLayoutList.AddTail(new Layout(wnd, tl_type, tl_margin, br_type, br_margin, hscroll, refresh));
}




void CResizableFormView::ArrangeLayout()
{
...
...
...
 
CSize TotalSize = GetTotalSize ();
 
//What is bigger. Actual Window or Initial Framesize.
//If the actual Window is bigger, we couldn't have scrollbars
int nMaxBreiteFenster = max (wndrc.Width(), TotalSize.cx);
int nMaxHoeheFenster = max (wndrc.Height(), TotalSize.cy);
 

// calculate new top-left corner
newrc.left = pl->tl_margin.cx + nMaxBreiteFenster * pl->tl_type.cx / 100;
newrc.top = pl->tl_margin.cy + nMaxHoeheFenster * pl->tl_type.cy / 100;
// calculate new bottom-right corner
newrc.right = pl->br_margin.cx + nMaxBreiteFenster * pl->br_type.cx / 100;
newrc.bottom = pl->br_margin.cy + nMaxHoeheFenster * pl->br_type.cy / 100;
// jms - 11/28/00 - new code starts
// Restrict controls from being sized smaller than their size on
// the dialog template. I could have mingled this code with the original
// four lines above, but I wanted Paolo to be abe to easily find what I
// did.
// FORMCONTROL* pCtrl = GetFormControl(pl->hwnd);
// newrc.left = max(newrc.left, pCtrl->rect.left);
// newrc.top = max(newrc.top, pCtrl->rect.top);
// newrc.right = max(newrc.right, pCtrl->rect.right);
// newrc.bottom = max(newrc.bottom, pCtrl->rect.bottom);
// jms - 11/28/00 - new code stops
 
//Die Scrollviews stehen irgendwo. Linke obere Ecke berechnen
//Calculate the offset between (0,0) of Form and visible area
CPoint ScrollPos = GetScrollPosition ();
newrc.top -= ScrollPos.y;
newrc.left -= ScrollPos.x;
newrc.bottom-= ScrollPos.y;
newrc.right -= ScrollPos.x;
 

 
// ORIGINAL CODE FROM HERE
if (!newrc.EqualRect(&objrc))
......
......
 
}
 


I changed following line for testing. Don't know if it changes something.
if (pl->adj_hscroll ) // changed in ->
if (pl->adj_hscroll && NULL)
You can (if it works) of course delete the whole if () {...} thing
 
I hope this was at least a little understandably.
Ciao
Siegmund
GeneralDemo LinkmemberAsha_krishna10 Jul '03 - 13:27 
The link for the demo project does not seem to work at all. Could anyone please update it?
If some one has a copy of the project, could you please email it to asha_krishna@yahoo.com
 
Thanks,

GeneralDemo download link not workingmemberLobster B15 May '03 - 20:17 
Hi,
The Demo download link in the article is not working anymore. Can anyone who already has this project, please mail me the same to lob_b(AT)hotmail.com
 
Thanks in advance
-Lobster B
Questionwhere is formview2.dsp file ???memberijt7epn30 Dec '02 - 5:09 
Sorry, I did not see formview2.dsp file in the zip file.
GeneralFit a dialog into a WindowmemberAnonymous17 Apr '02 - 6:47 
I have a dialog whose width is greater that main frame window.
 
Now I need to fit this dialog into the view and provide scrolling features to have a look at the complete dialog.
How do I do this?
 

GeneralUpdated ArticlememberJohn Simmons / outlaw programmer7 Jun '01 - 1:58 
I added the new version of OnInitialUpdate() to the article (the source code did not change).
Questionis ResizeParentToFit() compulsory ????memberwimel16 May '01 - 3:15 
You did a nice job by making this class. It very usefull.Smile | :)
But I don't wanna resize the parent. In my SDI-app with CSplitterWnd I wanna resize the formview to the parent.
 
Is this possible ?
what about GetParentFrame()->RecalcLayout()?
 
Any help is welcome
 

wimel
AnswerRe: is ResizeParentToFit() compulsory ????memberJohn Simmons / outlaw programmer17 May '01 - 2:51 
I don't quite understand what you want, but you don't have to use ResizeParentToFit(). All that does is makes the parent just large enough to display the entire dialog template used for the formview. Just comment that line out, and you should be set.
 

AnswerRe: is ResizeParentToFit() compulsory ????memberJohn Simmons / outlaw programmer17 May '01 - 3:14 
I just trie removing the call to resizeparent, and now the for doesn't resize/reposition the controls at all. Hmmm.
GeneralRe: is ResizeParentToFit() compulsory ????memberwimel22 May '01 - 21:29 
and there my problem....
I wanna keep the parent the same size when I'm changing views.
Without ResizeParentToFit() the controls aren't scaling well.
 
I tried to figure out what's happening in ResizeParentToFit()
 
Do u have any suggestions ?
 

 
THNX
GeneralRe: is ResizeParentToFit() compulsory ????memberJohn Simmons / outlaw programmer24 May '01 - 4:04 
Here's a new version of OnInitialUpdate which does what I think you want done.
 
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();
 
	CRect rectFrame;
	CFrameWnd* pFrame = GetParentFrame();
	ASSERT_VALID(pFrame);
	pFrame->GetWindowRect(rectFrame);
	CSize size = rectFrame.Size();
 
	ResizeParentToFit(FALSE);
 
	AnchorControls();
 
	pFrame->MoveWindow(rectFrame, TRUE);
}
This version of the function will allow you to keep your dialog template the desired sie (important for scrollbar stuff), will resize the frame to what the app set it to initially, *and* will resize the controls correctly.
 
Put the body of this function into your own derived class's OnInitialUpdate() function.

GeneralRe: is ResizeParentToFit() compulsory ????memberWimel7 Jun '01 - 1:26 
It's exactly what I need. Thnx a lot ! Rose | [Rose]
Is there a way to avoid the flickering when loading?
I'm changing the view each time when the selection in a treeview changed.
 

wimel
GeneralRe: is ResizeParentToFit() compulsory ????memberJohn Simmons / outlaw programmer7 Jun '01 - 1:44 
If it's flickering when the view is being initially displayed (for the first time), try this code in OnInitialUpdate(). If it's flickering when you're updating the view, try this code in OnUpdate() or OnDraw():
 
   SetRedraw(FALSE);
 
   //
   // the original contents of your OnUPdate function goes here
   //

   SetRedraw(TRUE);
   UpdateWindow();
 
I havn't tried it myself, but it may work.
 

GeneralActiveX controls and scrollingmemberShane Warren2 Apr '01 - 10:18 
First off, great class I've found it very useful. Poke tongue | ;-P
 
I noticed one strange thing though. Place a COM control (try the MSMask control) onto a resizable form. Resizing works fine at first glance. Now make the form smaller than its original size (until scroll bars appear), and click on the vertical scroll bar (I'm not positive its only vertical, but for me it seems to be). The ActiveX control "jumps" back to its original position until you resize the form, this its highly annoying. The only fix I've been able to come up with is to disable scrolling, but I'm afraid something else will make the control "jump" back to its original position too.
GeneralFix for disappearing radio buttons/checkboxesmemberMatt Philmon8 Mar '01 - 19:13 
Hi,
 
I was having problems with Paolo's CResizableDialog class. When I anchored checkboxes or radio buttons within a group box they disappeared completely. I sent Paolo an example project and he immediately found and fixed the problem. The same thing needs fixing in your FormView example here.
 
// add the style 'clipsiblings' to a GroupBox
// to avoid unnecessary repainting of controls inside
if (st == "BUTTON")
{
DWORD style = GetWindowLong(wnd, GWL_STYLE);
if (style & BS_GROUPBOX)
SetWindowLong(wnd, GWL_STYLE, style | WS_CLIPSIBLINGS);
}
 
must change to this:
// add the style 'clipsiblings' to a GroupBox
// to avoid unnecessary repainting of controls inside
if (st == "BUTTON")
{
DWORD style = GetWindowLong(wnd, GWL_STYLE);
if ((style & 0x0FL) == BS_GROUPBOX)
SetWindowLong(wnd, GWL_STYLE, style | WS_CLIPSIBLINGS);
}
 
This fixes my problems with his class (and your wrapper of it)
 
Thanks,
Matt PhilmonSmile | :)
GeneralRe: Fix for disappearing radio buttons/checkboxesmemberJohn Simmons / outlaw programmer15 Mar '01 - 6:22 
I haven't updated the code here yet, but I did make the hange in my source. Thanks for the tip.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 7 Jun 2001
Article Copyright 2000 by John Simmons / outlaw programmer
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid