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):
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 !