In my previous entry, I provided a class derived from CEdit the provides a clickable button within the control’s window. However, that code only allows the button to have textual content.
This entry will expand upon that code to allow any kind of content to be drawn. The goal here is to allow some kind further derived class to override a few simple functions to customize the button content.
Note: I actually had this improvement already worked out before I wrote the previous entry. So certain bits of code were conveniently placed in member functions when they wouldn’t have needed to be so for that first entry.
One thing to notice that helps make this change easy is that once the button width has been determined, most of the code does not care about the button’s content at all. So making CalculateButtonWidth virtual accomplishes everything necessary to allow a derived class to determine the size of the button.
The code that actually draws the button is also easy to deal with. There are just essentially two parts to the code from the first entry: 1) part for drawing the button frame and background 2) part for drawing the text.
So the text-drawing part can just be pulled out into a virtual DrawButtonContent function. That function will be called by DrawButton and passed the current device context as well as the rectangle for the content to be drawn in.
Of course, just for good measure, DrawButton itself could be virtual too. This allows for a derived class to completely take over the button drawing if it really wants to.
The changes I’ve described would be sufficient to allow a derived class to draw the button content in other ways. However, in the case where non-textual content is drawn, it wouldn’t make much sense for that derived class to still have the members for getting and setting the button text.
To deal with that, I’ve refactored the majority of the code into a class called CEditWithButton_Base. All of the text-related pieces are then pulled into a derived class, leaving DrawButtonContent and CalculateButtonWidth as pure virutals in the base class.
So a derived class that provides a textual button ends up being just:
class CEditWithButton : public CEditWithButton_Base
// The given text will be displayed in the button.
explicit CEditWithButton(LPCTSTR pszButtonText = _T("..."));
// Gets/Sets the button text.
CString GetButtonText() const;
void SetButtonText(LPCTSTR buttonText);
virtual void DrawButtonContent(CDC& dc, CRect rectButton);
virtual int CalculateButtonWidth();
with those functions implemented in obvious ways.
It should be easy to see how a different class could be derived to provide a button that displays some sort of graphical content or whatever else might be desired.
The code is available here.
My next post will deal with making this code work with the visual themes used in modern version of Windows.