Subclassing
Dialog Controls
Site Map Feedback
Up Calendar ColorButton CListCtrl DragBar Icons Subclassing

It's Easy to Add Functionality to Windows Controls!

So you want to use a Control, but the one provided by windows doesn't quite do everything you want...
Or, perhaps you just want a simple CWnd that gives you access to all the events
You've seen other programs do what you want, so it must be possible...
But how do you add functionality to a control?
From code examples available on the Web, there seem to be lots of ways...
Most of them are quite involved.
Fortunately there is a single line of code that does the job - all you need to do is understand what it does!
So...
First tackle extending a control's functionality:
You want, for example, a Tree Control but you need it to Load and Save (Serialize) its data.
First you create a class derived from CTreeControl:
class CSerializingTree : public CTreeCtrl {
public:
  CSerializingTree() {}
  virtual ~CSerializingTree() {}

  void Serialize(CArchive& ar);
};
Then you create an instance of it to use (in your Dialog class header file):
CSerializingTree SerializingTree;
Now put a Tree Control on your dialog box (it is assumed that you've left it called IDC_TREE1 here).
This makes it easy for you to add a client edge and use Class Wizard to create Event Handlers.
Now all that's left is to tell windows that the Control on your Dialog box is to represent your subclassed Tree...
This is one line of code put in your OnInitDialog() Event Handler:
SerializingTree.SubclassDlgItem(IDC_TREE1,this);
This is so easy to use once you know it, but knowing about it seems to be very rare!

Now, on to accessing the fundamental events of a simple control: CButton.
The easiest way is [View Menu][ClassWizard][Add Class...][New...]
Set [Base Class] to CButton and Name to CMyButton and all that's left is to create event handlers and an instance in your application.
Here's a good routine to demonstrate the use of an unusual CButton Event handler:
void CMyButton::OnMouseMove(UINT nFlags, CPoint point) {
  CRect rect; // Get the bounds of the control (just the client area)
  GetClientRect(rect);
  static bool WasIn=false; // Check the mouse is inside the control
  if(rect.PtInRect(point)) {
    if(!WasIn) { // This is the OnMouseEnter area
      SetWindowText("Over");
      SetCapture();
    }else SetWindowText("Moved Again");  // This else wouldn't normally be used.
    WasIn=true;
  }else{ // This is the OnMouseLeave area:
    SetWindowText("Out");
    ReleaseCapture();
    WasIn=false;
  }
  CButton::OnMouseMove(nFlags, point);
}
There are three ways to Create control instances:
  1. Use ClassWizard to create a Member Variable:
    Create a control on your dialog,
    go to [View Menu][ClassWizard][Member Variables][Select your Dialog Class][Select your Control][Add Variable...] give it a name.
  2. Attach the control manually (if you're not using DoDataExchange):
    Create a control on your dialog,
    add
    CMyButton MyButton;
    to your Dialog Header file,
    add
    MyButton.SubclassDlgItem(IDC_BUTTON1,this);
    to your Dialog Class OnInitDialog() Method.

  3. Create the control dynamically:
    add
    CMyButton MyButton;
    to your Dialog Header file,
    add
    MyButton.CreateEx(...);
    to your Dialog Class OnInitDialog() Method.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.