Introduction
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 ASSERT
s. 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 CEdit
s, 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, CIconEdit
handles WM_SIZE
and WM_SETFONT
. As 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.
History
15/6 2004
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*