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

Comments

  • I have a different problem

    Posted by Hyd on 11/05/2008 07:13pm

    Can i use include "color.h" from multiple header files for the same Workspace. Ex: I have 2 dialogs and each of them has bunch of button controls. If i include the color.h header file for one dialog it works fine. But if i include the header for a different file but all is basically located in one workspace. It throws class type redefinition. does someone has clue on this?

    • Re: I have a different problem

      Posted by cilu on 11/07/2008 01:47am

      You should be able to include use this class in as many dialogs as you want. Your description is confusing. You say "include the color.h header file for one dialog", but I guess you mean "in a dialog". You say "but all is basically located in one workspace" but you didn't explain whether it's a single project, or different projects. Please clarify these.

      Reply
    Reply
  • Great Article, it works(VC++ 6.0)

    Posted by Hyd on 11/05/2008 06:24pm

    I've created my own colorbutton header and cpp files by taking most of the hints provided in this article. Dont forget to check Owner Draw style for the control. Thank you so much the article was very helpful.

    Reply
  • Coun't get it to work in 2005

    Posted by TJS on 12/06/2007 03:44pm

    I just wnat to change the color of a button's text and background window.
    HBRUSH CTestThingsDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
    {
    	if(pWnd->GetDlgCtrlID() == IDC_BUTTON1);
            {
              // What code do I add here ??
            } 
    	return (HBRUSH) CreateSolidBrush(RGB(255,0,0));
    }

    Reply
  • Enabling and disabling CColorButton

    Posted by toneymathew on 11/29/2005 01:00pm

    I use the CColorButton and found that disabling the button using EnableWindow(bool) doesnt actually disable the window but only changes the color of the button (to the disable color I specified at creation). Any clues?

    Reply
  • Couldnt get it working in my app

    Posted by toneymathew on 09/12/2005 12:22pm

    I was relieved to find this on codeguru and actually ran the demo, it worked just fine. I did the exact thing as you did, created a text button, made it a CColorButton and then tried changing the color in initDialog, it goes through the over-ridden SetColor function but never calls the OnDraw in the CColorObject. So, I dont see the color change in my app. I also created a sample dialog app, to make sure I didnt fiddle with any settings and mess it up. No difference, please help

    • I'm facing the same Problem, Can You please help!

      Posted by Hyd on 11/05/2008 05:19pm

      I'm facing the same problem. Included the ColorButton.h and ColorButton.cpp in my app. Then created a button of type CColorButton and used the button.SetColor in InitDialog. Also added the DDX_Control(pDX, IDC_BUTTON1, m_button1); to the message map. When i run the app i dont see the color i set using the SetColor. Can you please let me know if i'm missing something. I need to implement this functionality very soon for some client. Appreciate your help. Thanks,

      Reply
    Reply
  • How you have added the skin

    Posted by baji_ou on 05/23/2005 08:16am

    Hi, thanks for your nice article, the image of the application in the article is looking very nice, how you have added the skin to the application. I want my application should use some skin. Please suggest me how can I add skin & how to use the skin controls. Have you used any activex control for it, if so please suggest me the way, how can I add skin, I have tested one activex control in vb called vbskinner, now in vc++ how to access that. Please suggest me.

    • re: skin

      Posted by baji_ou on 05/23/2005 03:40pm

      Thank you Marius, but do you have any idea, how we can add some skin to an application , I just want to change the look of my application. I am sorry for wasting your precious time :), infact I am searching for the same around.

      Reply
    • re: skin

      Posted by baji_ou on 05/23/2005 03:27pm

      Thank you Marius, but do you have any idea, how we can add some skin to an application , I just want to change the look of my application. I am sorry for wasting your precious time :), infact I am searching for the same around.

      Reply
    • re: re: skin

      Posted by cilu on 05/23/2005 03:25pm

      This is rather a forum question (you should ask it in the forum). Here is a link for you http://www.appspeed.com/.

      Reply
    • re: skin

      Posted by baji_ou on 05/23/2005 03:10pm

      Thank you Marius, but do you have any idea, how we can add some skin to an application , I just want to change the look of my application. I am sorry for wasting your precious time :), infact I am searching for the same around.

      Reply
    • re: skin

      Posted by cilu on 05/23/2005 02:03pm

      No. Sorry, no skin what so ever. I just put the controls on the dialog and aranged them.

      Reply
    • regarding skin

      Posted by baji_ou on 05/23/2005 12:36pm

      Hi, thanks for your reply! but, the image of the application you have given in the article I thought you have used some skin or some control to produce the final output. I want to give the similar kind of a look to my application. Can you please help me.

      Reply
    • skin?

      Posted by cilu on 05/23/2005 08:21am

      What skin are you talking about? I use no activeX or dlls for skinning the demo project. The button is a custom owner draw control. For other controls you can handle WM_CTLCOLOR if you want to change to colors. Check MSDN for more.

      Reply
    Reply
  • Sorry for my question and thank your answer

    Posted by xiayingang on 05/16/2005 02:09am

    i'm sorry for yesterday's question ,yesterday i only see your .exe ,today i see your source ,i found it is easey to change the size use you resource ,but i think if you packge it to your ColorButton class is a good idea

    • answer

      Posted by cilu on 05/16/2005 02:59am

      There's no problem with your question. However, as I said, since changing the font is not a button specific operation, but is done the same way for all controls, I would like to keep it as it is, by inheriting CWnd's SetFont() behaviour and not providing anything specific to this custom control.

      Reply
    Reply
  • anther question ???------>hwo to change the size of the text on button

    Posted by xiayingang on 05/15/2005 05:26am

    I'm glad to see your ColorButton Class ,but i think she is not a perfect Button Class ,if you enhance the ColorButton Class and make it have the function of change the text size on the button,then three will have a lot of people to respect you .

    • Sorry for my question

      Posted by xiayingang on 05/16/2005 12:58am

      i'm sorry for yesterday's question ,yesterday i only see your .exe ,today i see your source ,i found it is easey to change the size use you resource ,but i think if you packge it to your ColorButton class is a good idea

      Reply
    • how to change the font

      Posted by cilu on 05/15/2005 05:46am

      That functionality is not button specific. See this link for changing the font for a control: http://www.codeguru.com/forum/showthread.php?t=321408

      Reply
    Reply
  • A Small Question

    Posted by mfc_oracle on 11/11/2004 04:04am

    Very nice and useful classes thanks a lot! However, could I know how I can remove the dynamically created button without closing the dialog?

    • remove the dinamically created button

      Posted by cilu on 11/12/2004 05:45am

      Just as you remove any dynamically created control. If you just want to hide it (for the button in my demo):
      
      [code]
      m_dynamic->ShowWindow(SW_HIDE);
      [/code]
      
      If you want to destroy it:
      
      [code]
      m_dynamic->DestroyWindow(); // must be called first
      delete m_dynamic;
      m_dynamic = NULL;
      [/code]
      
      In the case of my demo CColoredButtonDlg::DestroyWindow()should be modified to test if m_dynamic is NULL before calling DestroyWindow() to avoid an invalid call.
      
      [code]
      BOOL CColoredButtonDlg::DestroyWindow() 
      {
      	fontVerdana->DeleteObject();
      	delete fontVerdana;
      	
      	fontGeorgia->DeleteObject();
      	delete fontGeorgia;
      
      	if(m_dynamic != NULL)
      	{
      		m_dynamic->DestroyWindow();
      		delete m_dynamic;
      		m_dynamic = NULL;
      	}
      	
      	return CDialog::DestroyWindow();
      }
      [/code]

      Reply
    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

Most Popular Programming Stories

More for Developers

RSS Feeds