Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Some Mix-in classes that give your ATL/WTL program a better appearance

0.00/5 (No votes)
18 Apr 2004 3  
This article discusses some MixIn classs for WTL. These MixIn classes provides some features that WTL/ATL framework does not support, such as owner-draw menu, skinned dialog buttons and static text controls.

Contents

Introduction

I have been a MFC programmer for a long time, it is a very nice framework. But MFC also has some disadvantages especially on the plan and development for little memory-resident program. For that kind of program, we prefer that the program has less size, occupy less resources and is without resource leaks. Obviously, that's not the advantage of MFC, so I begin to study WTL. Not like MFC, WTL has no Built in support for Owner-Drawn Menu. I had wrote the CMenuHelp class for the plain WTL window to skin the window's popup menu. CWzButtonImpl is a simple Owner-Drawn Button class, it cooperates with CButtonHelp which uses CWzButtonImpl to subclass all buttons in a dialog. CButtonHelp can also cooperate with other Owner-Drawn Button class. CCtrlColor processes WM_CTLCOLORDLG and WM_CTLCOLORSTATIC messages of dialog window, uses the template parameters to change the background color of dialog and controls' text color.

Since I'm not the expert on WTL/ATL framework, I can't ensure the code can work for everyone. Any advice are welcomed. You may notice that this article has many syntax errors or even totally wrong words sometimes, that's because I am not an English speaker. I hope everyone can understand this article.

CMenuHelp

As we known that when a menu will be popup, windows system send the WM_INITMENU and WM_ENTERMENULOOP message to the owner window of this menu and when it disappears, windows system sends the WM_EXITMENULOOP message to the owner window. If the menu items has MFT_OWNERDRAW attribute, windows will ALSO send WM_MEASUREITEM to measure the menu items and send WM_DRAWITEM message to let the owner window draw the menu items.

CMenuHelp is a template class, It is also a MixIn class. It handles that 5 messages of the owner window; in WM_INITMENU message handle, it gets the handle of active menu (the menu is not show out yet) and calls AttachActiveMenu() to add MFT_OWNERDRAW attribute to all menu items in this menu. When the menu disappears, DetachActiveMenu() will be invoked, this method removes the MFT_OWNERDRAW attribute that was added by AttachActiveMenu().

Properties of CMenuHelp

HMENU CMenuHelp::m_hActiveMenu

Store the handle of the menu that will pop-up, OnMeasureItem and OnDrawItem uses this handle to take some operation on the pop-up menu.

COLORREF CMenuHelp::m_crText

Color to be used to draw the normal menu item text.

COLORREF CMenuHelp::m_crHiText

Color to be used to draw the selected menu item text.

COLORREF CMenuHelp::m_crBkGnd

Color to be used to draw the background of menu item.

COLORREF CMenuHelp::m_crHiBkGnd

Color to be used to draw the background of selected menu item.

Methods of CMenuHelp

HMENU CMenuHelp::AttachActiveMenu(HMENU hActiveMenu)

Attach the menu handle which will pop-up to m_hActiveMenu. hActiveMenu is the handle of new menu. AttachActiveMenu() will add MFT_OWNERDRAW attribute to all menu items in this menu, so the system will send WM_MEASUREITEM and WM_DRAWITEM messages to our window. CMenuHelp handles the two messages to draw the menu. AttachActiveMenu() returns the last popup menu handle.

HMENU CMenuHelp::DetachActiveMenu()

Remove MFT_OWNERDRAW attribute from all menu items of m_hActiveMenu and set m_hActiveMenu to NULL. It returns the handle of current pop-up menu.

Use CMenuHelp in your code

It's easy to use this class in your code. Inlude "MenuHelp.h" to your project, add CMenuHelp to the derivation chain of your window, like this:
  class CMainDlg : public CDialogImpl<CMainDlg>,
    public CMenuHelp<CMainDlg>
and last, add declaration information to message chain:
BEGIN_MSG_MAP(CMainDlg)
  ...
  CHAIN_MSG_MAP(CMenuHelp<CMainDlg>)
  ...
END_MSG_MAP()
it works, all popup menu of this window will be draw by our CMenuHelp instead of Windows normal menu appearance.

CButtonHelp

CButtonHelp is a helper class to change the appearance of button controls in a dialog. It modifies and adds BS_OWNERDRAW property to all pushbuttons when a dialog initialize itself, link these button controls to CWzButtonImpl class. CWzButtonImpl is the real Owner-Draw button class. CWzButtonImpl uses SubclassWindow to take over the measure and draw behaviors of standard Windows button, like most other MFC's CButton deriving classes.

CWzButtonImpl

CWzButtonImpl is a Owner-Draw button class derived from CButton(ATL class), It is easy to use like most MFC's Owner-Draw button class. Declare a CWzButtonImpl object first and then call SubclassWindow method to attach it to a pushbutton control. You can modify the drawing code in this class to change the appearance of button control if you don't like the current style. You can also replace this class by other Owner-Draw button class, You can find many just in CodeProject. You can also specify several different Owner-Draw button class (style) in your apps, but can only one class in a dialog.

Property of CButtonHelp

CSimpleArray<t_ButtonClass *> CButtonHelp::m_arButtons

Store all t_ButtonClass objects in the dialog, and every t_ButtonClass object attaches to a pushbutton. t_ButtonClass is a template parameter, it should be CWzButtonImpl in our example code.

Method of CButtonHelp

BOOL CButtonHelp::SubclassAllButtons()

Attach pushbuttons in dialog to t_ButtonClass class objects. It usually will be a call in initial function of a window, such as CDialog::OnInitDialog.

BOOL CButtonHelp::SubclassButton(HWND hBtnWnd)

Create a t_ButtonClass object and attach it to a normal pushbutton control. hBtnWnd is the HWND of the button control.

BOOL CButtonHelp::UnSubclassButton(HWND hBtnWnd)

Detach a t_ButtonClass object from pushbutton control. hBtnWnd is the HWND of the button contol. The t_ButtonClass object will be delete from CMenuHelp::m_arButtons.

int CButtonHelp::FindButtons(HWND hBtnWnd)

To make sure whether a pushbutton control had been subclassed already.

Use CButtonHelp in your code

Include ButtonHelp.h to your project firstly, and then add CButtonHelp class to the derivation chain of dialog,like this:
class CMainDlg : public CDialogImpl<CMainDlg>, 
   public CButtonHelp<CMainDlg,CWzButtonImpl>
finally, don't forget call SubclassAllButtons() in CDialog::OnInitDialog.

CCtrlColor

CCtrlColor class handles some of WM_CTLCOLOR* messages (current support only for WM_CTLCOLORDLG and WM_CTLCOLORSTATIC), draw the controls in dialog using special text color and background color (specified by template parameter). It is a quite simple class, just 34 lines C++ code.

Property of CCtrlColor

HBRUSH CCtrlColor::m_brBkgnd

HBRUSH GDI object

CCtrlColor class uses this brush to paint the background of dialog and controls. CCtrlColor creates this object in constructor function; use color specified by template parameter t_crBkgnd, and delete this object in destruct function.

Use CCtrlColor in your code

CCtrlColor has three template parameters : T, t_crTextColor and t_crBkgnd. The last two are optional, they have default value as RGB(64,64,255) and RGB(222,222,222). So you can add CCtrlColor to the derivation chain of your dialog in two methods:

class CMainDlg : public CDialogImpl<CMainDlg>, 
   public CCtrlColor<CMainDlg>
or
class CAboutDlg : public CDialogImpl<CAboutDlg>, 
   public CCtrlColor<CAboutDlg,RGB(64,128,64)>
the same as CMenuHelp, adding declaration information to message chain:
BEGIN_MSG_MAP(CMainDlg)
  ...
  CHAIN_MSG_MAP(CCtrlColor<CMainDlg>)
  ...
END_MSG_MAP()

About the demo code

All source codes are organized in a VC6 project, it is not tested with VC7 compiler. Since this article is talking about ATL/WTL, you should also install WTL for compiling the source code. There is no limit on using this code, it can be use in any purposes.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here