While adding controls to other controls might be a commonly desired task, and edit box with an icon is perhaps not the most exciting or useful class. It presents a few enjoyable challenges, however, and usefulness is certainly not the only criteria for diving into control subclassing in MFC.
CIconEdit is a small
CEdit-derived class with an attached small icon, where the multi line edit box edit rectangle is exploited, instead of the normal handling of non-client areas.
Using the code
Include the cpp- and h-file to the project.
CIconEdit can be instantiated either dynamically, by a call to
Create, or from a dialog template. In the latter case, a control variable can be created and bound to the control with the class wizard, or
SubclassDlgItem can be used. Call
SetIcon with either a
HICON or a resource id to set the icon to display.
CIconEdit uses the edit rectangle of multi line edit boxes. Basically, it modifies the edit rectangle to add a left margin wide enough to accommodate a small icon. An instance of
CIconWnd - a
CStatic-derived class - is used to paint the icon. Icons can be set by calling
CIconEdit::SetIcon with either a
HICON handle to the desired icon, or a
UINT resource id. If a resource id is used, the icon is destroyed by
CIconEdit, otherwise the caller will have to destroy it.
The class overrides
PreSubclassWindow. This call checks the edit box style. If
ES_MULTILINE is not set,
SetRect will not work, so the function
ASSERTs. Sadly, it is not possible to add this style after the control is created - and it is too early to destroy and recreate the it. Then the edit rectangle is established. The width of a small icon is retrieved by a call to
GetSystemMetrics, and the current edit rectangle is fetched, updated and set back to the control.
As soon as an icon is set by a call to either of the two
SetIcon:s, the icon window is created.
CIconWnd is a very simple
CStatic-derived class, handling
WM_PAINT and there drawing the icon with a call to
::DrawIconEx. The icon will be scaled to the system small icon size if necessary.
Points of interest
Instantiating this control, doing a few common operations on
CEdits, displayed an understandable but annoying quirk - the edit rectangle is reset. As the rectangle is absolute for a
CEdit (RTF-controls can use an offset),
WM_SIZE will have to be handled anyway. More surprising was that
WM_SETFONT also killed the edit rectangle. For this reason,
SetFont is not virtual, the message itself will have to be handled.
In this case, using a separate control for the icon might seem a bit byzantine, why not just draw it in the non-client area paint handling? Well, now I got myself a small-icon control if I should ever need one (which I doubt), and the edit control and icon is thoroughly separated codewise.
But the more exciting implication is the possibility to use the edit rectangle to put other controls and/or visuals in the edit box, buddy-buttons, line-numbers etc. And as the editing rectangle is not only used by the plain vanilla edit box - the RTF-control also has one - there is the possibility to add rulers etc. this way.
In an explosion of activity, this article is finally updated thanks to the feedback from David Pritchard . I'm getting the system background color using
GetSysColor(COLOR_WINDOW) when clearing the background behind the icon, and
SetIcon with the
HICON parameter will now also create the icon control... *blushing with embarrassment*