Enhanced Colored Button

This button is based on the work of John Wellbelove, January 8, 2002.

A problem with push button controls is that you cannot change the default drawing colors. WM_CTLCOLOR does not work for push buttons. The only way to use other colors for a push buttons is to use an owner-draw button and do the drawing by yourself.

By using CColorButton, you can:

  • Change, at any time, any of the seven colors needed to draw a button
  • Align the text at any position
  • Use multi-line text
  • Create buttons dynamically
  • Change the default font of the text

What Does CColorButton Bring New?

In addition to previous controls, CControlButton allows the usage of multiline text. You can do this either by checking the multiline option in the Styles tab from the Properties window of the button, or by using the BS_MULTILINE flag when creating the control. BS_MULTILINE flag can be added to the button styles or removed from them by using the GetWindowLong and SetWindowLong methods. Lines are separated by using .\n.. See the example in the "How to Create a Dynamic CColorButton" section.

The first example here shows how to remove the multiline style, and the second how to add it.

void CColoredButtonDlg::OnButton1()
{
   DWORD dwStyles = GetWindowLong(m_dynamic->GetSafeHwnd()
                                  GWL_STYLE);
   dwStyles &= ~BS_MULTILINE;
   SetWindowLong(m_dynamic->GetSafeHwnd(), GWL_STYLE, dwStyles);
   m_dynamic->SetWindowText("Dynamic Created");
   m_dynamic->Invalidate();
}


void CColoredButtonDlg::OnButton3()
{
   DWORD dwStyles = GetWindowLong(m_dynamic->GetSafeHwnd(),
                                  GWL_STYLE);
   dwStyles |= BS_MULTILINE;
   SetWindowLong(m_dynamic->GetSafeHwnd(), GWL_STYLE, dwStyles);
   m_dynamic->SetWindowText("Dynamic\nCreated");
   m_dynamic->Invalidate();
}

CControlButton also allows text alignment in different vertical and horizontal positions. You can set the position of the text either from the Styles tab of the Properties window of the button (Horizontal Alignment and Vertical Alignment combo boxes) or by using the BS_TOP, BS_VCENTER, or BS_BOTTOM flags for vertical alignment, and BS_RIGHT, BS_CENTER, and BS_LEFT for horizontal alignment.

Here is an example of how to change the alignment of the button text from left to right.

void CColoredButtonDlg::OnButton6()
{
   DWORD dwStyles = GetWindowLong(m_dynamic->GetSafeHwnd(),
                                  GWL_STYLE);
   dwStyles &= ~BS_LEFT;
   dwStyles |= BS_RIGHT;
   SetWindowLong(m_dynamic->GetSafeHwnd(), GWL_STYLE, dwStyles);
   m_dynamic->Invalidate();
}

CColorButton Header

class CColorButton : public CButton
{
private:
   enum {BUTTON_IN           = 0x01,
         BUTTON_OUT          = 0x02,
         BUTTON_BLACK_BORDER = 0x04,};

// Construction
public:
   CColorButton();
   CColorButton(COLORREF text, COLORREF bkgnd);
   CColorButton(COLORREF text, COLORREF bkgnd, COLORREF disabled);
   CColorButton(COLORREF text, COLORREF bkgnd, COLORREF disabled,
                COLORREF light, COLORREF highlight,
                COLORREF shadow, COLORREF darkShadow);

// Attributes
public:

private:
   COLORREF m_TextColor;
   COLORREF m_BkgndColor;
   COLORREF m_DisabledBkgndColor;
   COLORREF m_Light;
   COLORREF m_Highlight;
   COLORREF m_Shadow;
   COLORREF m_DarkShadow;

// Operations
public:
   void SetColor(COLORREF text, COLORREF bkgnd);
   void SetColor(COLORREF text, COLORREF bkgnd, COLORREF disabled);
   void SetColor(COLORREF text, COLORREF bkgnd, COLORREF disabled,
                 COLORREF light, COLORREF highlight,
                 COLORREF shadow, COLORREF darkShadow);
   void SetColorToWindowsDefault();

private:
   void DrawFrame(CDC *pDC, CRect rc, int state);
   void DrawFilledRect(CDC *pDC, CRect rc, COLORREF color);
   void DrawLine(CDC *pDC, long sx, long sy, long ex, long ey,
                 COLORREF color);
   void DrawButtonText(CDC *pDC, CRect rc, CString strCaption,
                       COLORREF textcolor);

// Overrides
   // ClassWizard generated virtual function overrides
   //{{AFX_VIRTUAL(CColorButton)
   public:
   virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
   //}}AFX_VIRTUAL

// Implementation
public:
   virtual ~CColorButton();

   // Generated message map functions
protected:
   //{{AFX_MSG(CColorButton)
   afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
   //}}AFX_MSG

   DECLARE_MESSAGE_MAP()
};

CColorButton has several contructors, allowing you to set the colors of the button. Colors also can be set by using the overloaded SetColors() method. By default, the colors used are system's ones.

If you want to set the colors to those used by the system to draw the button, call SetColorsToWindowsDefault().

How to Use CColorButton

  • Include colorbutton.h and colorbutton.cpp in your project.
  • Add a button to your resource dialog, (e.g. IDC_BUTTON_COLOR).
  • Include colorbutton.h in your dialog class header.
  • Using ClassWizard and a control variable for the button (e.g. m_button).
  • Replace CButton with CColorButton as the type of the new added control variable:
  • CColorButton m_button;
  • In OnInitDialog(), set the colors for the button.
  • m_button1.SetColor(RGB(255,0,0), RGB(255,255,255));
  • Compile and run.

How to Create a Dynamic CColorButton

  • Declare a variable in your header:
  • CColorButton* m_dynamic;
  • Create the button in OnInitDialog:
  • m_dynamic = new CColorButton(BLUE, LBLUE);
    m_dynamic->Create("Dynamic\nCreated",
                      WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|
                      BS_OWNERDRAW|BS_MULTILINE,
                      rc,this,IDC_BUTTON_DYN);
    m_dynamic->ShowWindow(SW_SHOW);
    
  • Make sure you destroy it when the dialog is closed:
  • BOOL CColoredButtonDlg::DestroyWindow()
    {
       m_dynamic->DestroyWindow();
       delete m_dynamic;
       m_dynamic = NULL;
    
       return CDialog::DestroyWindow();
    }
    


About the Author

Marius Bancila

Marius Bancila is a Microsoft MVP for VC++. He works as a software developer for a Norwegian-based company. He is mainly focused on building desktop applications with MFC and VC#. He keeps a blog at www.mariusbancila.ro/blog, focused on Windows programming. He is the co-founder of codexpert.ro, a community for Romanian C++/VC++ programmers.

Downloads