Owner Draw Button Step-by-Step

Environment: VC++6
I think some of you may not like the buttons in Windows. Sometimes, I think they're ugly. Fortunately, we can change the appearance of our buttons by overriding the DrawItem function of the CButton class. I 'm going to demonstrate the steps of the owner drawing button. In this article, I will make a class, which inherits from CButton class.
The edit window is displaying the IDD_OWNERDRAWBUTTON_DIALOG. We have to make our class first, so we don't have time to look at this dialog. Go to the ClassView, right-click "OwnerDrawButton classes", and choose "New class". For the class type, just leave the default "MFC Class". In the "Name" editbox, type "CMyButton" (just an example). Choose "CButton" from the "Base Class".
You have added a new class; it's time to override the DrawItem function. Right-click "CMyButton" in ClassView and choose "Add Virtual Function". The "New Virtual Override for class CMyButton" page opens. Double-click "DrawItem" in the left "New Virtual Functions" listbox. Afterward, 'DrawItem" will jump to the right "Existing virtual function overrides" listbox. Finally, press OK to add a new virtual override.
Go to the implementation of CMyButton::DrawItem, which is in MyButton.cpp. Add draw code in this function. Here is my drawing code to demonstrate how to use CDC to draw it.
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { CDC dc; dc.Attach(lpDrawItemStruct->hDC); //Get device context object CRect rt; rt = lpDrawItemStruct->rcItem; //Get button rect dc.FillSolidRect(rt, RGB(0, 0, 255)); //Fill button with blue color UINT state = lpDrawItemStruct->itemState; //Get state of the button if ( (state & ODS_SELECTED) ) // If it is pressed { dc.DrawEdge(rt,EDGE_SUNKEN,BF_RECT); // Draw a sunken face } else { dc.DrawEdge(rt,EDGE_RAISED,BF_RECT); // Draw a raised face } dc.SetTextColor(RGB(255,255,120)); // Set the color of the caption to be yellow CString strTemp; GetWindowText(strTemp); // Get the caption which have been set dc.DrawText(strTemp,rt,DT_CENTER|DT_VCENTER|DT_SINGLELINE); // Draw out the caption if ( (state & ODS_FOCUS ) ) // If the button is focused { // Draw a focus rect which indicates the user // that the button is focused int iChange = 3; rt.top += iChange; rt.left += iChange; rt.right -= iChange; rt.bottom -= iChange; dc.DrawFocusRect(rt); } dc.Detach(); }
Your job isn't finished yet. Go back to the ResourceView and click "IDD_OWNERDRAWBUTTON_DIALOG". Yes, you are right! You are going to edit your dialog box. Drag a button to the dialog box. Now, modify its properties by right-clicking it and choosing "Properities". For its ID, call it "IDC_COLOREDBUTTON" and caption it "Colored Button". You also have to allow it to be owner draw. Go to the Styles tab and check "Owner Draw". Then, close the Properties dialog box.
You have to link this button to the CMyButton class. Press Ctrl+W to open the MFC Class Wizard. Under the "Member variables" page, double-click "IDC_COLOREDBUTTON", which is in the "Control IDs" listbox. You are then brought to the "Add Member Variable" dialog. For the "Member variable name", type "m_MyColoredButton". For the "Variable Type", choose "CMyButton", and then press OK. VC++ will inform you to check if there is an include statement in "OwnerDrawButtonDlg.h". You won't find it, so add #include "MyButton.h" at the beginning of OwnerDrawButtonDlg.h.
Press F7 to build your project. Afterward, run it and you will see the same as the picture at the beginning of this article.
This is the first time for me to write an English article. Feel free to give some bad comments to me. I am glad to read them.
Comments
Thank you.
Posted by Goldstone on 05/12/2013 05:02pmThank you for very helpful information
ReplyGreat. A good and nice simple solution.
Posted by vladovidiu on 11/08/2005 06:27amI just love simple solutions. And if you create the button dynamically it works like a charm.
ReplyBitmapped Button
Posted by Legacy on 02/26/2004 12:00amOriginally posted by: BIGBUBBA
I love your example on the colored button. Its easy to understand. I was wondering if you could explain how to do the same thing but for a button that is an icon? I looked on here for bitmapped button. I simply could not understand the guy cause evidently some steps were skipped.
ReplyThanks
Tony
What about a CFormView based Classe?
Posted by Legacy on 10/14/2003 12:00amOriginally posted by: Lslx
Hi,
I try almost all exemples on this thread and I'm still not able to use a custom button on a CFormView class.
So I add a button in my CFormView ressource, set the ownerdraw to true and give a new ID. After, I add a variable in my CFormView with class wizard( So the DDX stuff appear).
When I start my program, I have an assertion faillure in the CButton::DrawItem function.
Have an hint?
I also tried that: don't put a control button in the ressource editor and "Create" my button in the CMyFormView::OnCreate(...) fonction. like:
CRect rect(80,80,14,14);
m_myButton.Create("C",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, rect, this, IDC_MYBUTTON);
But, nothing appear!
Thanks,
Lslx
answer
Posted by Mahmoud on 04/01/2016 01:52pmif you set the "Owner Draw" flag as true and forget to overweight "DrawItem" virtual function, You will get "assertion failure" error. go ahead and overwrite the function.
ReplyThanks a lot!!
Posted by Legacy on 09/30/2003 12:00amOriginally posted by: Louis
Thanks for the detail instruction.
It does help me very much.
Reply
Didnt work for me
Posted by Legacy on 09/22/2003 12:00amOriginally posted by: Jellow
Didnt work for me. Simply followed what you said. No errors. Nothing. But no result. But I didnt add a new button. But used for a button that was already existing and was functional. Any problem??
ReplyThen modified the project to use the class with a newly added button resource. Even then no expected result obtained. What can be the reason?
Thank you
Posted by Legacy on 07/09/2003 12:00amOriginally posted by: HyunMin
Thank you for very helpful information
Suggestion
Posted by Legacy on 03/31/2003 12:00amOriginally posted by: Ed
You need to move the text down and to the right 2 pixels when the button is depressed.
Thanks for the idea, though.
Reply
Thank you - needed the intro.
Posted by Legacy on 02/25/2003 12:00amOriginally posted by: hjd_uk
Thanks, just what i needed to start me off using Owner Draw objects.
Reply
How to get default background color of a button
Posted by Legacy on 02/21/2003 12:00amOriginally posted by: Mark
Thank you for this wonderful example. It has saved me much time. I am trying to expand it by allowing a button to be one color under certain circumstances, and under others, look like all the other normal buttons. So, at runtime I know which way I want it, and its easy to use your code to set the text and background color of the button on the fly, but I can not figure out how to set the background color back to the original color. What I have tried is ::GetDC()->GetBKColor() but this seems to alwyas be white. Any help is much appreciated.
Mark
The repainting:
Dlg::OnPaint()
{
...
if ( bPreviousIncidents )
{
m_odbtnPreviousIncidents.m_clrBackground = RGB(255, 0,0); // Red
m_odbtnPreviousIncidents.m_clrText = RGB(0,0,255); // Blue
}
else
{
// Get from another button
COLORREF clrBackground = m_btnSameIncident.GetDC ( )->GetBkColor ( );
m_odbtnPreviousIncidents.m_clrBackground = clrBackground;
COLORREF clrText = m_btnSameIncident.GetDC ( )->GetTextColor ( );
m_odbtnPreviousIncidents.m_clrText = clrText;
}
...
}
The owner draw class:
void COwnerDrawButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
//Get device context object
CDC dc;
dc.Attach(lpDrawItemStruct->hDC);
//Get button rect
CRect rt;
rt = lpDrawItemStruct->rcItem;
// Fill button with passed in color
dc.FillSolidRect(rt, m_clrBackground);
//Get state of the button
UINT state = lpDrawItemStruct->itemState;
// If it is pressed
if ( (state & ODS_SELECTED) )
{
// Draw a sunken face
dc.DrawEdge(rt,EDGE_SUNKEN,BF_RECT);
}
else
{
// Draw a raised face
dc.DrawEdge(rt,EDGE_RAISED,BF_RECT);
}
// Set the color of the caption to be yellow
dc.SetTextColor(m_clrText);
CString strTemp;
// Get the caption which have been set
GetWindowText(strTemp);
// Draw out the caption
dc.DrawText(strTemp,rt,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
// If the button is focused
if ( (state & ODS_FOCUS ) )
{
// Draw a focus rect which indicates the user
// that the button is focused
int iChange = 3;
rt.top += iChange;
rt.left += iChange;
rt.right -= iChange;
rt.bottom -= iChange;
dc.DrawFocusRect(rt);
}
dc.Detach();
Reply}
Loading, Please Wait ...