Sizing Dialog Box

Environment: Windows NT4 SP5, Visual C++ 6 SP3

Have you ever made sizing dialog boxes? Well I’ve made some (with my bare hands and a bit MFC support). Well
it was quite a hack.

Later on, I’ve found some code on CodeGuru that made the whole thing
much easier, but I didn’t like the approach: Deriving your dialog box from some
other class or having a member variable, handing it the sizing factors I want.
Well it’s quite easy, but this is layout, and layout is something I want to do
in the Resource Editor. My code is complex enough without sizing dialogs. (And,
by the way: none of the approaches works for VB or some other language)


So here is my suggestion: You make the dialog box. You turn on the “Sizing
border” attribute. You insert the “Sizing Dialog control”. Done


You can watch how your controls resize in as you test your dialog from the resource editor (remember:
you haven’t compiled once until now, nor have you made any code changes!)


There are two ways to use the control:


In Proportional mode all controls are kept at their relative positions. That
is, if a control starts at let’s say 30% of the dialog width, and takes 20% of
the dialog’s width, it will always start at 30%, and take 20%, no matter how
many pixels that is. The controls behave like they’ve been stretchblit’d (of
course, I don’t really make a stretchblt)


In Normal mode, you have 9 fixed positions as shown below (the grey area marks the control):


Sample Image


A control that is completely in the “left, centered”
will always stay left, centered. If the top-left edge of a control is in
the “left, centered” area, and it’s bottom-right edge is in the “centered,
bottom” area, the two edges will move seperately. (English is not my first
language, so you may prefer to look at the control’s behaviour yourself…)


As I’ve said, I have made a few sizable dialogs, and this is what I’ve done
most of the times. However, if you don’t mind a bit of code, you can still
change the sizing behavior (seperately for each of your controls) through the
control’s properties.


So now, the interface:

Note from Web Master : The following code was reformatted (each
method was broken into two lines) so that it would display
properly in our current format.


interface ISizeCtrl : IDispatch
{
[propget, id(1), helpstring(“Property Proportional”)]
HRESULT Proportional([out, retval] BOOL *pVal);

[propput, id(1), helpstring(“Property Proportional”)]
HRESULT Proportional([in] BOOL newVal);

[propget, id(2), helpstring(“Property MinX”)]
HRESULT MinX([out, retval] double *pVal);

[propput, id(2), helpstring(“Property MinX”)]
HRESULT MinX([in] double newVal);

[propget, id(3), helpstring(“Property MinY”)]
HRESULT MinY([out, retval] double *pVal);

[propput, id(3), helpstring(“Property MinY”)]
HRESULT MinY([in] double newVal);

[propget, id(4), helpstring(“Property MaxX”)]
HRESULT MaxX([out, retval] double *pVal);

[propput, id(4), helpstring(“Property MaxX”)]
HRESULT MaxX([in] double newVal);

[propget, id(5), helpstring(“Property MaxY”)]
HRESULT MaxY([out, retval] double *pVal);

[propput, id(5), helpstring(“Property MaxY”)]
HRESULT MaxY([in] double newVal);

[propget, id(6), helpstring(“Property HandleMinMaxInfo”)]
HRESULT HandleMinMaxInfo([out, retval] BOOL *pVal);

[propput, id(6), helpstring(“Property HandleMinMaxInfo”)]
HRESULT HandleMinMaxInfo([in] BOOL newVal);

[propget, id(7), helpstring(“Property PosChangeX”)]
HRESULT PosChangeX([in] long hwndChild, [out, retval] double *pVal);

[propput, id(7), helpstring(“Property PosChangeX”)]
HRESULT PosChangeX([in] long hwndChild, [in] double newVal);

[propget, id(8), helpstring(“Property PosChangeY”)]
HRESULT PosChangeY([in] long hwndChild, [out, retval] double *pVal);

[propput, id(8), helpstring(“Property PosChangeY”)]
HRESULT PosChangeY([in] long hwndChild, [in] double newVal);

[propget, id(9), helpstring(“Property SizeChangeX”)]
HRESULT SizeChangeX([in] long hwndChild, [out, retval] double *pVal);

[propput, id(9), helpstring(“Property SizeChangeX”)]
HRESULT SizeChangeX([in] long hwndChild, [in] double newVal);

[propget, id(10), helpstring(“Property SizeChangeY”)]
HRESULT SizeChangeY([in] long hwndChild, [out, retval] double *pVal);

[propput, id(10), helpstring(“Property SizeChangeY”)]
HRESULT SizeChangeY([in] long hwndChild, [in] double newVal);

[propget, id(11), helpstring(“Property PosChangeXId”)]
HRESULT PosChangeXId([in] long idChild, [out, retval] double *pVal);

[propput, id(11), helpstring(“Property PosChangeXId”)]
HRESULT PosChangeXId([in] long idChild, [in] double newVal);

[propget, id(12), helpstring(“Property PosChangeYId”)]
HRESULT PosChangeYId([in] long idChild, [out, retval] double *pVal);

[propput, id(12), helpstring(“Property PosChangeYId”)]
HRESULT PosChangeYId([in] long idChild, [in] double newVal);

[propget, id(13), helpstring(“Property SizeChangeXId”)]
HRESULT SizeChangeXId([in] long idChild, [out, retval] double *pVal);

[propput, id(13), helpstring(“Property SizeChangeXId”)]
HRESULT SizeChangeXId([in] long idChild, [in] double newVal);

[propget, id(14), helpstring(“Property SizeChangeYId”)]
HRESULT SizeChangeYId([in] long idChild, [out, retval] double *pVal);

[propput, id(14), helpstring(“Property SizeChangeYId”)]
HRESULT SizeChangeYId([in] long idChild, [in] double newVal);

};


Big interface, isn’t it? Well, you don’t have to use it
if you only want the normal behaviour.


The first property exposes the settings I’ve already
explained: Proportional/Normal. Then there are those “MinX, MaxX, MinY,
MaxY” properties. Those control how much the dialog can be resized (values in
percentage of the original size) If you want to handle WM_MINMAXINFO yourself,
simply set HandleMinMaxInfo to FALSE, which is the default. All these properties
are available in the resource editor trough the contol’s property
sheet.


The following properties: PosChangeX/Y, SizeChangeX/Y
control the sizing behaviour of each individual element in your dialog. This way
you can tell just what HWND should resize how. (Example:
PosChangeX(m_btnOk.GetSafeHWnd, 0.2) means that if you make the dialog 100
pixels bigger, the OK-Button will move 20 pixels (that is 100*0.2) to the right.
These changes have to made at run-time (e.g. in OnInitDialog).


PosChangeX/YId and SizeChangeX/YId do the same as their
non-Id counterparts, but they take a Dialog-Item ID (IDOK, IDC_EDIT1…) instead
of a
HWND.


So now, how have I done all
this?


Magic!


Ok, I’ll tell you: It took me quite a time to figure out
how to intercept the messages from a parent window (I’ve tried Hooks,
timers, and other things you sure don’t want to know about), until I found a
handy ATL class named CContainedWindow. I simply tell this window to
“SubclassWindow(GetParent())” and – magic – I recieve my parent’s messages
like my own ones. I can even decide whether to forward those messages to my
parent or eat them all myself at runtime. (As the name suggests,
CContainedWindow is usually used only for child windows, however, subclassing
works for parent or even completely unrelated windows just as well). The rest is
quote straightforward: I keep a map with a HWND-WndPos mapping inside, and
iterate through all child windows on a WM_SIZE, to adjust their
size.


A last note: The source code is documented, and should
not be hard to understand. Unfoutunately, I’m working with a german version of
VisualStudio, so some of the Wizard’s comments are still german. I assume you
know what the wizard would write, and I assume you don’t really need his
comments. All my comments are in
english.


If
you like the code, give it to your
friends. If you don’t, try to give it to your enemies. If
you have any suggestions how to improve the usability of this control, feel free to
email at me niki.estner@cube.net
!

Downloads


Download Source – 18 Kb

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read