This example demonstrates how to create a button whose color may be changed
at runtime. It relies on a class written by Bob Ryan which was subsequently
modified by R. Wuppinger.
A simple project with a working button is available here.
Figure 1: Example application
The basic steps are to
- Create an MFC application,
- Add one or more button(s) using the class wizard,
Figure 2: Added Button1
- Add the CColorButton class files
(colorBtn.h and colorBtn.cpp)
to the project,
- Create a CColorButton object for each button you
wish to color,
- Attach each button control to the corresponding color button object,
- Make sure the button has the Owner Draw style
selected (rigth click on button, Properties -> Styles ->
Owner Draw), and
Figure 3: "Owner Draw" selected
- Use CColorButton::SetColor to set the color of the
button.
I have included snips of the code from the
buttonColoring project along with the source
code for the CColorButton class.
1// buttonColoringDlg.h : header file
2//
3
4#include "colorBtn.h" // CCT
.
. SNIP
.
35protected:
36 HICON m_hIcon;
37
38 CColorButton m_button1; // CCT
.
. SNIP
.
54#endif // !defined(AFX_BUTTONCOLORINGDLG_H__359741D6_4334_4185_A496_19A2442ADB05__INCLUDED_)
1// buttonColoringDlg.cpp : implementation file
2//
3// All modifications to the default MFC project are denoted with a "// CCT"
4// at the end of the line // CCT
5// Important: Push Button Properties -> Styles -> Owner Draw must be checked // CCT
6#include "stdafx.h"
7#include "buttonColoring.h"
8#include "buttonColoringDlg.h"
9#include "colorBtn.h" // CCT
.
. SNIP
.
94
95BOOL CButtonColoringDlg::OnInitDialog()
96{
.
. SNIP
.
122 // TODO: Add extra initialization here
123 m_button1.Attach(IDC_BUTTON1, this); // CCT
124
125 return TRUE; // return TRUE unless you set the focus to a control
126}
.
. SNIP
.
177// t a y l o r@msoe.edu, 6-13-2002 // CCT
178void CButtonColoringDlg::OnButton1()
179{
180 // TODO: Add your control notification handler code here
181 static int currentColor = 0;
182 switch (currentColor) {
183 case 0:
184 m_button1.SetColor(BLACK, BLUE);
185 currentColor = 1;
186 break;
187 case 1:
188 m_button1.SetColor(BLACK, RED);
189 currentColor = 2;
190 break;
191 case 2:
192 m_button1.SetColor(BLACK, YELLOW);
193 currentColor = 3;
194 break;
195 default:
196 m_button1.SetColor(BLACK, GREEN);
197 currentColor = 0;
198 break;
199 }
200}
1//----------------------------------------------------
2// colorBtn.h : changed by r. wuppinger
3//----------------------------------------------------
4
5#ifndef __COLORBTN_H__
6#define __COLORBTN_H__
7
8/////////////////////////////////////////////////////////////////////////////
9// colorBtn.h : header file for the CColorButton class
10//
11// Written by Bob Ryan (ryan@cyberzone.net)
12// Copyright (c) 1998.
13//
14// This code may be freely distributable in any application. If
15// you make any changes to the source, please let me know so that
16// I might make a better version of the class.
17//
18// This file is provided "as is" with no expressed or implied warranty.
19// The author accepts no liability for any damage/loss of business that
20// this product may cause.
21//
22/////////////////////////////////////////////////////////////////////////////
23
24const COLORREF CLOUDBLUE = RGB(128, 184, 223);
25const COLORREF WHITE = RGB(255, 255, 255);
26const COLORREF BLACK = RGB(1, 1, 1);
27const COLORREF DKGRAY = RGB(128, 128, 128);
28const COLORREF LTGRAY = RGB(192, 192, 192);
29const COLORREF YELLOW = RGB(255, 255, 0);
30const COLORREF DKYELLOW = RGB(128, 128, 0);
31const COLORREF RED = RGB(255, 0, 0);
32const COLORREF DKRED = RGB(128, 0, 0);
33const COLORREF BLUE = RGB(0, 0, 255);
34const COLORREF DKBLUE = RGB(0, 0, 128);
35const COLORREF CYAN = RGB(0, 255, 255);
36const COLORREF DKCYAN = RGB(0, 128, 128);
37const COLORREF GREEN = RGB(0, 255, 0);
38const COLORREF DKGREEN = RGB(0, 128, 0);
39const COLORREF MAGENTA = RGB(255, 0, 255);
40const COLORREF DKMAGENTA = RGB(128, 0, 128);
41
42
43#define CB_BG_DEFAULT LTGRAY
44#define CB_FG_DEFAULT BLACK // black text
45#define CB_SID_DEFAULT DKGRAY // dark gray disabled text
46
47
48class CColorButton : public CButton
49{
50DECLARE_DYNAMIC(CColorButton)
51public:
52 CColorButton();
53 virtual ~CColorButton();
54
55 BOOL Attach(const UINT nID, CWnd* pParent,
56 const COLORREF BGColor = CB_BG_DEFAULT, // gray button
57 const COLORREF FGColor = CB_FG_DEFAULT, // black text
58 const COLORREF DisabledColor = CB_SID_DEFAULT, // dark gray disabled text
59 const UINT nBevel = 2
60 );
61
62 void SetFGColor( COLORREF color = CB_FG_DEFAULT, BOOL bRedraw=FALSE) { m_fg = color; if(bRedraw)
63InvalidateRect(NULL);}
64 void SetBGColor( COLORREF color = CB_BG_DEFAULT, BOOL bRedraw=FALSE) { m_bg = color; if(bRedraw)
65InvalidateRect(NULL);}
66 void SetDisabledColor(COLORREF color = CB_SID_DEFAULT, BOOL bRedraw=FALSE) { m_disabled= color;
67if(bRedraw) InvalidateRect(NULL);}
68
69 void SetColor( COLORREF colFG = CB_FG_DEFAULT, COLORREF colBG= CB_BG_DEFAULT, COLORREF colDIS =
70CB_SID_DEFAULT, BOOL bRedraw=TRUE)
71 { SetFGColor( colFG);
72 SetBGColor( colBG);
73 SetDisabledColor(colDIS);
74 if(bRedraw) InvalidateRect(NULL);
75 }
76
77protected:
78 virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);
79 void DrawFrame(CDC *DC, CRect R, int Inset);
80 void DrawFilledRect(CDC *DC, CRect R, COLORREF color);
81 void DrawLine(CDC *DC, CRect EndPoints, COLORREF color);
82 void DrawLine(CDC *DC, long left, long top, long right, long bottom, COLORREF color);
83 void DrawButtonText(CDC *DC, CRect R, const char *Buf, COLORREF TextColor);
84
85 COLORREF GetFGColor() { return m_fg; }
86 COLORREF GetBGColor() { return m_bg; }
87 COLORREF GetDisabledColor() { return m_disabled; }
88 UINT GetBevel() { return m_bevel; }
89
90private:
91 COLORREF m_fg, m_bg, m_disabled;
92 UINT m_bevel;
93
94};
95#endif
1
2
3//----------------------------------------------------
4// colorBtn.cpp : changed by r. wuppinger
5//----------------------------------------------------
6
7
8
9/////////////////////////////////////////////////////////////////////////////
10// colorBtn.cpp : implementation file for the CColorButton class
11//
12// Written by Bob Ryan (ryan@cyberzone.net)
13// Copyright (c) 1998.
14//
15// This code may be freely distributable in any application. If
16// you make any changes to the source, please let me know so that
17// I might make a better version of the class.
18//
19// This file is provided "as is" with no expressed or implied warranty.
20// The author accepts no liability for any damage/loss of business that
21// this product may cause.
22//
23/////////////////////////////////////////////////////////////////////////////
24
25
26#include "stdafx.h"
27#include "colorbtn.h"
28
29#ifdef _DEBUG
30#undef THIS_FILE
31static char BASED_CODE THIS_FILE[] = __FILE__;
32#endif
33
34// no automatic class substitution for this file!
35#ifdef CColorButton
36#undef CColorButton CColorButton
37#endif
38
39// CColorButton
40IMPLEMENT_DYNAMIC(CColorButton, CButton)
41
42CColorButton::CColorButton()
43{
44#if (_MFC_VER < 0x0250)
45 hwndOwner = NULL; // initialize hwndOwner for GetOwner() and SetOwner() support in MFC < 2.5
46#endif
47}
48
49
50
51CColorButton::~CColorButton()
52{
53}
54
55
56
57BOOL CColorButton::Attach(const UINT nID, CWnd* pParent, const COLORREF BGColor, const COLORREF FGColor,
58const COLORREF DisabledColor, const UINT nBevel)
59{
60 if (!SubclassDlgItem(nID, pParent))
61 return FALSE;
62
63 m_fg = FGColor;
64 m_bg = BGColor;
65 m_disabled = DisabledColor;
66 m_bevel = nBevel;
67
68 return TRUE;
69}
70
71
72void CColorButton::DrawItem(LPDRAWITEMSTRUCT lpDIS)
73{
74 CDC* pDC = CDC::FromHandle(lpDIS->hDC);
75
76 UINT state = lpDIS->itemState;
77 CRect focusRect, btnRect;
78 focusRect.CopyRect(&lpDIS->rcItem);
79 btnRect.CopyRect(&lpDIS->rcItem);
80
81 //
82 // Set the focus rectangle to just past the border decoration
83 //
84 focusRect.left += 4;
85 focusRect.right -= 4;
86 focusRect.top += 4;
87 focusRect.bottom -= 4;
88
89 //
90 // Retrieve the button's caption
91 //
92 const int bufSize = 512;
93 TCHAR buffer[bufSize];
94 GetWindowText(buffer, bufSize);
95
96
97 //
98 // Draw and label the button using draw methods
99 //
100 DrawFilledRect(pDC, btnRect, GetBGColor());
101 DrawFrame(pDC, btnRect, GetBevel());
102 DrawButtonText(pDC, btnRect, buffer, GetFGColor());
103
104
105 //
106 // Now, depending upon the state, redraw the button (down image) if it is selected,
107 // place a focus rectangle on it, or redisplay the caption if it is disabled
108 //
109 if (state & ODS_FOCUS) {
110 DrawFocusRect(lpDIS->hDC, (LPRECT)&focusRect);
111 if (state & ODS_SELECTED){
112 DrawFilledRect(pDC, btnRect, GetBGColor());
113 DrawFrame(pDC, btnRect, -1);
114
115
116// ----> Changes! // changes by RW:
117
118 // move the button text if it is pressed...
119 CRect rectPressedBtnText = btnRect;
120
121 // to the right and bottom...
122 rectPressedBtnText.OffsetRect( 1, 1 );
123
124 // ... and now paint it!
125 DrawButtonText(pDC, rectPressedBtnText, buffer, GetFGColor());
126
127 // DrawButtonText(pDC, btnRect, buffer, GetFGColor());
128 DrawFocusRect(lpDIS->hDC, (LPRECT)&focusRect);
129 }
130 }
131 else if (state & ODS_DISABLED) {
132 //COLORREF disabledColor = bg ^ 0xFFFFFF; // contrasting color
133 DrawButtonText(pDC, btnRect, buffer, GetDisabledColor());
134 }
135}
136
137
138void CColorButton::DrawFrame(CDC *DC, CRect R, int Inset)
139{
140 COLORREF dark, light, tlColor, brColor;
141 int i, m, width;
142 width = (Inset < 0)? -Inset : Inset;
143
144 for (i = 0; i < width; i += 1) {
145 m = 255 / (i + 2);
146 dark = PALETTERGB(m, m, m);
147 m = 192 + (63 / (i + 1));
148 light = PALETTERGB(m, m, m);
149
150 if ( width == 1 ) {
151 light = RGB(255, 255, 255);
152 dark = RGB(128, 128, 128);
153 }
154
155 if ( Inset < 0 ) {
156 tlColor = dark;
157 brColor = light;
158 }
159 else {
160 tlColor = light;
161 brColor = dark;
162 }
163
164 DrawLine(DC, R.left, R.top, R.right, R.top, tlColor);
165 // Across top
166 DrawLine(DC, R.left, R.top, R.left, R.bottom, tlColor);
167 // Down left
168
169 if ( (Inset < 0) && (i == width - 1) && (width > 1) ) {
170 DrawLine(DC, R.left + 1, R.bottom - 1, R.right, R.bottom - 1, RGB(1, 1, 1));// Across bottom
171 DrawLine(DC, R.right - 1, R.top + 1, R.right - 1, R.bottom, RGB(1, 1, 1)); // Down right
172 }
173 else {
174 DrawLine(DC, R.left + 1, R.bottom - 1, R.right, R.bottom - 1, brColor); // Across bottom
175 DrawLine(DC, R.right - 1, R.top + 1, R.right - 1, R.bottom, brColor); // Down right
176 }
177 InflateRect(R, -1, -1);
178 }
179}
180
181
182
183void CColorButton::DrawFilledRect(CDC *DC, CRect R, COLORREF color)
184{
185 CBrush B;
186 B.CreateSolidBrush(color);
187 DC->FillRect(R, &B);
188}
189
190
191void CColorButton::DrawLine(CDC *DC, CRect EndPoints, COLORREF color)
192{
193 CPen newPen;
194 newPen.CreatePen(PS_SOLID, 1, color);
195 CPen *oldPen = DC->SelectObject(&newPen);
196 DC->MoveTo(EndPoints.left, EndPoints.top);
197 DC->LineTo(EndPoints.right, EndPoints.bottom);
198 DC->SelectObject(oldPen);
199 newPen.DeleteObject();
200}
201
202void CColorButton::DrawLine(CDC *DC, long left, long top, long right, long bottom, COLORREF color)
203{
204 CPen newPen;
205 newPen.CreatePen(PS_SOLID, 1, color);
206 CPen *oldPen = DC->SelectObject(&newPen);
207 DC->MoveTo(left, top);
208 DC->LineTo(right, bottom);
209 DC->SelectObject(oldPen);
210 newPen.DeleteObject();
211}
212
213
214void CColorButton::DrawButtonText(CDC *DC, CRect R, const char *Buf, COLORREF TextColor)
215{
216 COLORREF prevColor = DC->SetTextColor(TextColor);
217 DC->SetBkMode(TRANSPARENT);
218 DC->DrawText(Buf, strlen(Buf), R, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
219 DC->SetTextColor(prevColor);
220}