The codex design MFC extension classes
(w)April.1998 codex design: Hans Bühler

[ http://www.codex.ro/ | mailto:hb@codex.ro ]

codex design
 

cdxCSizingDialog[CDialog],
cdxCSizingPropSheet[CPropertySheet] and cdxCSizingPropPage[CPropertyPage]
[ Introduction | Requirements | Files | How to use | Function reference | Tutorial ]
(Documentation; release 1; 1.5.1998)

Introduction:

Q: What is the difference between the following two dialogs ?

A: There is no difference !

The cdxCSizingDialog class is a class derived from CDialog making it very easy to implement sizable dialogs. I really missed that feature in VC++ (and IMHO it's a shame to the MFC that it doesn't provide an easy to use way to solve this problem).
However, now it is possible to make your dialogs sizable - you can add this to an existing dialog in three steps !

In addition to cdxCSizingDialog, you will even find both cdxCSizingPropSheet and cdxCSizingPropPage in the two files that are part
of the zip, but these are considered to be in beta stadium for now (they seem to work ... I only have problems with the sizing icon).

The most important features of cdxCSizingDialog are:

Requirements:

Files:

How to use:

  1. Every control on our dialog needs a DDX value of class control (use Class Wizard in the resource editor).
  2. In both the header and implementation file, replace all strings "CDialog" by "cdxCSizingDialog" and insert an #include "cdxCSizingDialog.h" to your header file.
  3. In OnInitDialog(), make a call to AddSzControl() for each control you want to resize/reposition if the dialog's size changes.
    A little tutorial can be found below.

Function reference:

cdxCSizingPropSheet

cdxCSizingPropPage

Construction/Initialization:

cdxCSizingDialog::cdxCSizingDialog():

Synopsis:

cdxCSizingDialog(UINT idd, CWnd *pParent = NULL, Freedom fd = fdAll, bool mkSizeIcon = true);
[protected]

Task:

Constructs the dialog class with the given Resource ID and parent window (see documentation of CDialog::CDialog() for further details).
Additionally, the freedom parameter allows you to decide whether you want your dialog class being sizable in both x and y direction or in only one of them and the mkSizeIcon boolean enables creation of a windows-style size icon in the lower right corner of your window.

Parameters:

  • UINT idd

  • The resource ID of the dialog resource.
  • CWnd *pParent

  • Pointer to the parent window or NULL.
  • Freedom fd

  • Freedom is an embedded enumerator of cdxCSizingDialog. It may have the following values:
  • fdAll

  • The dialog's size can be changed in both x and y direction.
  • fdHoriz

  • The dialog's size can only be changed in width.
  • fdVert

  • The dialog's size can only be changed in height.
  • bool mkSizeIcon

  • Set this to false if you don't like/need the icon (just leave it true to see what it is :^).

    cdxCSizingDialog::OnInitDialog():

    Synopsis:

    virtual BOOL OnInitDialog(UINT addSzByPcnt);
    virtual BOOL OnInitDialog();

    [protected]

    Task:

    Sets up the base cdxCSizingDialog object.
    Must be called before using AddSzControl()!

    Some word to the minimum size of your window:

    This function sets up various data which it gets from your dialog - it creates the dialog and reads its size which will be taken as the minimum size of the dialog.
    This convention had been made in order to allow you to design your dialog in a way that looks great even if the dialog is reduced to its minum size.
    On the other hand, this way also has a disadvantage: Most dialogs would look much nicer (and would be more easy to handle) if they get a reasonable bigger size than the minimum one.
    To solve this problem, next to the standard OnInitDialog(void) function exported by CDialog, you even find a second form allowing you to pass the addSzByPcnt parameter to the function. This parameter allows you to increase the size of the dialog automatically (thus the dialog won't appear in its minimum width but slightly bigger).

    OnInitDialog(void) is a short-cut to OnInitDialog(UINT addSzByPcnt) passing cdxCSizingDialog::DEF_STRETCH (which is 10) to it.

    Parameters:

    • addSzByPcnt

    • This parameter will be passed to StrechWindow() if non-zero, increasing the size of the window by
      newSize = originalSize + (originalSize * addSzByPcnt) / 100.
      See StretchWindow() for more information.

    Remarks:

    Since the size of the dialog may change during the call to OnInitDialog() (and to a subsequent call to RestoreWindowposition() if you use this function), I recommend to design your dialog without the WS_VISIBLE flag and to use CDialog::ShowWIndow(SH_SHOW) just before you finish your own OnInitDialog().

    An example code would could like:

    BOOL MyDialog::OnInitDialog()
    {
      BOOL b = cdxCSizingDialog::OnInitDialog();

      // add your controls

      AddSzControl(m_wndAnyControl,mdRepos,mdRepos);
      ...

      // modify controls (add columns to controls etc...)

      ...

      // load window position from registry

      RestoreWindowPosition(_T("MyDialog_Position"));

      // finally, show window

      ShowWindow(SW_SHOW);

      return b;
    }

    See also:

    cdxCSizingDialog(), AddSzControl(), RestoreWindowPosition(), StretchWindow(), CDialog::ShowWindow()

    Adding controls:

    cdxCSizingDialog::AddSzControl():

    Synopsis:

    void AddSzControl(CWnd & ctrl, Mode modeX = mdNone, Mode modeY = mdNone);
    void AddSzXControl(CWnd & ctrl, Mode modeX);
    void AddSzYControl(CWnd & ctrl, Mode modeY);
    [protected]

    Task:

    Tells the underlaying cdxCSizingDialog about a dialog control that should react on changes to the size of the dialog. You have to call this function for each control that should change its position and/or size in x and/or y direction.
    AddSzXControl() and AddSzYControl() are simple short-cut inlines for AddSzControl().

    Parameters:

    • CWnd & ctrl

    • The control.
    • Mode modeX

    • Defines the way the control reacts on changes to the dialog's width; for possible values see below.
    • Mode modeY

    • Defines the way the control reacts on changes to the dialog's height; for possible values see below.
      Mode is an embedded enumerator of cdxCSizingDialog.
      It may have the following values (given we talk about the x-dimension, i.e. the width of the dialog):
      • mdNone

      • Nothing. The control remains in its position and size ("control sticks to the left of the dialog").
      • mdRepos

      • The control moves to the right if the control's width increases ("control sticks to the right of the dialog").
      • mdResize

      • The control's width grows if the dialog's width grows ("sizing the dialog even sizes the control").
      • mdRelative

      • The control's position will be kept relative to the dialog's width; its size won't change ("keeps centered controls being centered"): If the dialog's width increases by 100, the control will be moved to the left by 50.
    Even note the description in the tutorial, if things are not clear yet.

    Remarks:

    See also:

    OnInitDialog(), AddSzControlEx()

    cdxCSizingDialog::AddSzControlEx():

    Synopsis:

    void AddSzControlEx(CWnd & ctrl, BYTE dX1pcnt, BYTE dX2pcnt, BYTE dY1pcnt, BYTE dY2pcnt);
    void AddSzXControlEx(CWnd & ctrl, BYTE dX1pcnt, BYTE dX2pcnt);
    void AddSzYControlEx(CWnd & ctrl, BYTE dY1pcnt, BYTE dY2pcnt);
    [protected]

    Task:

    This is the advanced version of AddSzControl(), which makes use of this function.
    AddSzXControlEx() and AddSzYControlEx() are simple short-cut inlines for AddSzControlEx().

    Parameters:

    • CWnd & ctrl

    • The control.
    • BYTE dX1pcnt, BYTE dX2pcnt, BYTE dY1pcnt, BYTE dY2pcnt

    • These values describe how to manipulate the four position values left (x1), top (y1), right (x2) and bottom (y2) of the control ctrl.
      These values are positive percent values. If the dialog changes its size, the difference between its initial (i.e. minimum) size will be calculated (deltaX and deltaY) and the values x1-y2 will be set to their initial values plus pcnt percent of the appropiate delta value.

      Use the value cdxCSizingDialog::exIgnore(0) to say that a value should not be used (the appropiate position value will stay untouched in all cases) or cdxCSizingDialog::exMaximum(100) to apply the maximum value.

    An example:

    Let's say the initial left position (x1) of the control is 10, the initial size of the dialog is 100 and you set the appropiate pcnt value (dX1pcnt) to 50.

    • Now the dialog's widht changes from 100 to 140:
    • The difference between the initial widht and the current one is 140-100 = 40.

    • dX1pcnt percent of 40 means 50 percent of 40 = 20.
      => Therefore the left position of the control will be set to 10(x1) + 20(deltaX*dX1pcnt/100) = 30.
    In short, the following formulas are used:
    • x1 = init_x1 + ( (dlg_cur_wid - dlg_init_wid) * dX1pcnt ) / 100
    • x2 = init_x2 + ( (dlg_cur_wid - dlg_init_wid) * dX2pcnt ) / 100
    • wid = init_wid + ( ( dlg_cur_wid - dlg_init_wid) * (dX2pcnt - dX1pcnt) ) / 100
    • y1 = init_y1 + ( (dlg_cur_hi - dlg_init_hi) * dY1pcnt ) / 100
    • y2 = init_y2 + ( (dlg_cur_hi - dlg_init_hi) * dY2pcnt ) / 100
    • hi = init_hi + ( ( dlg_cur_hi - dlg_init_hi) * (dY2pcnt - dY1pcnt) ) / 100
    Where init_x1,...,init_y2 describe the initial position of the control, dlg_init_hi and dlg_init_wid is the initial and dlg_cur_wid and dlg_cur_hi the current size of the dialog itself (all client-rect).

    Remarks:

    Here's which values AddSzControl() will pass to AddSzControlEx() depending on the cdxCSizingDialog::Mode modeX value used (explanation for the x dimension; will be similar for y):
     
      dX1pcnt dX2pcnt
    mdNone 0 0
    mdRepos 100 100
    mdResize 0 100
    mdRelative 50 50
     
    Important:
    This function will not check the validity of the values you provide - for example if you set dX1pcnt to 100 and dX2pcnt to 0 and the dialog will be enlarged by more than the initial width of your control, the control will be tried to be sized to a negative width !!!!!
    To ensure that your values never cause trouble, I recommend that dX1pcnt is always smaller or eqal to dX2pcnt (similar with dY1pcnt and dY2pcnt, of course :).

    See also:

    OnInitDialog(), AddSzControlEx()

    Additional utility functions:

    cdxCSizingDialog::RestoreWindowPosition():
    cdxCSizingDialog::StoreWindowPosition():

    Synopsis:

    bool RestoreWindowPosition(const CString & profileSec, bool withState = false);
    bool StoreWindowPosition(const CString & profileSec);

    bool RestoreWindowPosition(UINT strId, bool withState = false);
    bool StoreWindowPosition(UINT strId);
    [public]

    Task:

    This pair of function might be used to store and load the position and size of the dialog window to allow the user keep its preferred positioning available between two sessions with your program.
    As you may guess, StoreWindowPosition() saves the current window's coordinates and RestoreWindowPosition() is able to restore them, later.
    RestoreWindowPosition():
    This function should be used from within your dialog's OnInitDialog() function.
    Additionally, you should design your dialog without the WS_VISIBLE style and use CWnd::ShowWindow(SW_SHOW) to make it visible after calling this function (or you use withState = true).

    StoreWindowPosition():
    This function is recommended be used from within OnOK(), OnCancel() and OnClose() to ensure the position is saved in all cases.

    Parameters:

    • const CString & profileSec

    • A string that identifies the registry-section where the dialog's coordinates might be stored in.
      Inside the section, some values like "Left", "Top" etc. will be used. Note that you may even define several sub-sections by providing a string like "Document_1\\Properties\\Window" - see CWinApp::GetProfileString() for further details on profile sections.
    • UINT strId

    • Allows you to use a resource string ID instead of profileSec.
    • bool withState

    • If true, ResoreWindowPosition() even restores the states of the window (visible, minimized, maximized etc.), otherwise not.

    Return values:

    true if successful, false otherwise.

    See also:

    OnInitDialog()

    cdxCSizingDialog::StretchWindow():

    Synopsis:

    void StretchWindow(UINT addSzByPcnt = DEF_STRETCH);
    [public]

    Task:

    This function might be used to increase the window's size by a percentage value.

    Parameters:

    • UINT addSzByPcnt

    • How many percent of the current widht [heigt] shall be added to the width [height] of the dialog ?
      If you use 20, and the dialog is 100 pixels wide it will get 120 pixels wide.
      The default is cdxCSizingDialog::DEF_STRETCH, which currently is 10.

    cdxCSizingPropSheet, cdxCSizingPropPage:


    A quick tutorial:

    A. Setting it up

    1. We need Visual C++ ready.
    2. Create a new Workspace with a "dialog-based application" called Test.

    3. Among others, you will get the files TestDlg.h and TestDlg.cpp which describe your main dialog, CTestDlg which is associated to a dialog resource called IDD_TEST_DIALOG.
    4. Compile this project the first time to generate the procompiled header file.

    B. Installing the files and preparing the dialog class

    1. Copy the files cdxCSizingDialog.h and cdxCSizingDialog.cpp into your project's file directory.
    2. Open your Workspace-List "Files", select the treeview item Test files and use your right mouse-button to "Add files to project...".
    3. Select cdxCSizingDialog.h and cdxCSizingDialog.cpp.
    4. Open both TestDlg.h and TestDlg.cpp and open the "Search and replace"-dialog (Ctrl+h).

    5. Replace the string CDialog by cdxCSizingDialog in both files.
    6. Open the dialog's resource IDD_TEST_DIALOG, select the dialog and display its properties.

    7. Switch to the Styles tab and change the border from Dialog frame to Resizing.
    8. Compile your project and run the application - you can size your dialog and you see a little sizing icon in its lower right corner :)

    9. Moreover, the dialog won't be sizable smaller than it has been in the resource editor.

    C. Moving buttons

    1. Now we make the OK and Cancel button stick to the right side of your dialog:

    2. Open IDD_TEST_DIALOG in the resource editor (if you closed it before) and run the Class Wizard.
    3. Select the Member variables tab and double-click on the IDOK item to add a member variable:

    4. Name: m_wndOK
      Category: Control
      Type: CButton
    5. Do the same with IDCANCEL (Name: m_wndCancel).
    6. Switch to the Message Maps tab and double-click OnInitDialog() in the lower list-view.
    7. Scroll down until you find the // TO DO comment.
    8. Past the comment, add the following lines to the function:
    9. Compile and run your application.... fine, isn't it ??

    D. More advanced resizing and repositioning

    1. Change the lines you just added into:
    2. Run...
    3. What is it doing ?

    4. Well, AddSzControl() (or AddSzXControl()/AddSzYControl()) takes the control and automatically repositiones it in the x and y direction (the first parameter of AddSzControl() describes what to do if the width of the dialog changes, the second what to do if the height changes).
      That's what we needed, isn't it ?
      Of course, in addition to AddSzControl() there is a much more powerful function AddSzControlEx() which allows more precise positioning and resizing of controls (AddSzControl() takes the types mdNone, mdRepos, mdResize and mdRelative).

    E. Changing sizing freedom

    1. Open CTestDlg::TestDlg. It should look like this:
    2. Run... now the dialog's size is only changeable horizontally and the little sizing-icon has gone.

    F. Storing its position and size

    1. Open CTestApp::OnInitInstance(), scroll down and before the line that contains "CTestDlg dlg;", add the line:
    2. Open CTestDlg::OnInitDialog() again and - past your previously added lines, add the following line:
    3. Use the Class Wizard (via the resource editor) to add a message handler for IDOK/MB_CLICKED.
    4. Open CTestDlg::OnOK() and before cdxCSizingDialog::OnOK() is called, add the line
    5. Run your application, resize the window, click OK and restart it ...