Murali Devarakonda
asked on
Drawing a round-rectangle shaped button
I have a DialogBar on the frame of a Doc/View app. I'm using Visual C++ 5.0. I have a few buttons that I wish to draw in a round-rectangle shape, something like:
______
(______)
but obviously cleaner.
I'm relatively new to MFC GUI programming but I have been looking around, and I suppose the answer lies in one/some/a-combination of these keywords: owner-draw, MeasureItem, PresubClassWindow, DrawItem, CRgn::CreateRoundRectRgn.. .
Also, I'm not sure I understand the last two parameters to CRgn::CreateRoundRectRgn- can you explain?
Please be as specific as possible in your answer, as I have spent a considerable time on this problem. A code snippet would definitely be preferable. A sample would be great.
Thanx a lot!
______
(______)
but obviously cleaner.
I'm relatively new to MFC GUI programming but I have been looking around, and I suppose the answer lies in one/some/a-combination of these keywords: owner-draw, MeasureItem, PresubClassWindow, DrawItem, CRgn::CreateRoundRectRgn..
Also, I'm not sure I understand the last two parameters to CRgn::CreateRoundRectRgn- can you explain?
Please be as specific as possible in your answer, as I have spent a considerable time on this problem. A code snippet would definitely be preferable. A sample would be great.
Thanx a lot!
Check out the buttons section at http://www.codeguru.com. There are classes to create circular buttons and triangular buttons, adapting those classes to rounded rectangles should be easy.
Owner drawn buttons are fairly simple. Rectangular ones are easiest becaure you can use DrawFrameControl to draw them.
For other straight-edged shapes, you can use DrawEdge.
For a round rectangle, you need to do more of the drawing yourself (using RoundRect) after setting the pen and brush colours. If you want a 3D raised look (like standard button), then even that won't help and you'll need to draw the individual parts of the round rect in different colours (arcs and lines). If you want an Apple-look (I think they have round rects) then the round rect call would beok .. maybe with another round rect drawn first in black for a shadow.
BTW: The test of the button is drawn using DrawState.
If you want some code for doing owner drawn buttons, let me know.
For other straight-edged shapes, you can use DrawEdge.
For a round rectangle, you need to do more of the drawing yourself (using RoundRect) after setting the pen and brush colours. If you want a 3D raised look (like standard button), then even that won't help and you'll need to draw the individual parts of the round rect in different colours (arcs and lines). If you want an Apple-look (I think they have round rects) then the round rect call would beok .. maybe with another round rect drawn first in black for a shadow.
BTW: The test of the button is drawn using DrawState.
If you want some code for doing owner drawn buttons, let me know.
ASKER
Thank you for your response. Even before I posted my question, I had already looked at the CodeGuru samples (hence my reference to "PresubClassWindow, DrawItem, CRgn::CreateRoundRectRgn.. ." etc.
It's not obvious from the samples - at least not for someone new to Advanced GUI stuff in MFC- how I can reshape a rectangular button to round-rect. There seems to be an awful lot of code required (with a thorough understanding of the concepts behind it).
I expected it to be a straighforward task, if not trivial.
If that's not the case, I must say this is another reason MFC sucks because it's not very well designed, and not truly object-oriented. Why couldn't the CButton class (or it's derived) have methods to resize, reshape, etc.? Just wondering...
It's not obvious from the samples - at least not for someone new to Advanced GUI stuff in MFC- how I can reshape a rectangular button to round-rect. There seems to be an awful lot of code required (with a thorough understanding of the concepts behind it).
I expected it to be a straighforward task, if not trivial.
If that's not the case, I must say this is another reason MFC sucks because it's not very well designed, and not truly object-oriented. Why couldn't the CButton class (or it's derived) have methods to resize, reshape, etc.? Just wondering...
ASKER
RONSLOW,
I already have a standard rectangular button on my DialogBar. All I want to do is to give it semi-circular edges, keeping all the other properties intact. Of course, I'll be painting a bitmap onto it, which works so far ;-)
If you have a sample, please send it to Murali-Krishna@Cheerful.co m
Thanx!
I already have a standard rectangular button on my DialogBar. All I want to do is to give it semi-circular edges, keeping all the other properties intact. Of course, I'll be painting a bitmap onto it, which works so far ;-)
If you have a sample, please send it to Murali-Krishna@Cheerful.co
Thanx!
Windows supports some standard button shapes .. a rectangular push-button, a check box, a option(radio) button. Other non-standard shapes are drawn by overriding the DrawItem function, in which case you can draw them anyway you want. That seems fairly flexible to me.
Once you've done an ownerdrawn button once (or borrowed someone elses ownerdrawn button code) then you just change it to draw as you want using any of the good old GDI drawing functions. GDI includes DrawFrameControl, DrawState, DrawEdge, Draw3DRect and DrawFocusRect to help you.
Here is a DrawItem override that should do what you want (roughly .. I haven't compiled it .. treat it as pseudo-code if you like).
...
Once you've done an ownerdrawn button once (or borrowed someone elses ownerdrawn button code) then you just change it to draw as you want using any of the good old GDI drawing functions. GDI includes DrawFrameControl, DrawState, DrawEdge, Draw3DRect and DrawFocusRect to help you.
Here is a DrawItem override that should do what you want (roughly .. I haven't compiled it .. treat it as pseudo-code if you like).
...
#define ROUND
void CRoundRectButton::DrawBord ers(CDC* pDC, CRect& rect,UINT state) {
#ifdef ROUND
// black border, white inside
CPen edgepen(PS_SOLID,0,RGB(0,0 ,0));
CPen shadowpen(PS_SOLID,0,RGB(1 28,128,128 ));
CPen facebrush(RGB(255,255,255) );
CPen shadowbrush(RGB(128,128,12 8));
CPen* pOldPen = pDC->SelectObject(&shadowp en);
CBrush* pOldBrush = pDC->SelectObject(&shadowb rush);
// allow for shadow
rect.DeflateRect(1,1);
// setup roundness
CPoint roundness;
roundness.x = roundness.y = rect.Height()/2;
// draw shadow first
if (state & ODS_SELECTED) {
// draw shadow at topleft
rect.OffsetRect(0,0);
pDC->RoundRect(rect,roundn ess);
rect.OffsetRect(1,1);
} else {
// draw shadow at bottom right
rect.OffsetRect(1,1);
pDC->RoundRect(rect,roundn ess);
rect.OffsetRect(-1,-1);
}
// now draw the button over the top of the shadow
pDC->SelectObject(&facebru sh);
pDC->SelectObject(&edgepen );
pDC->RoundRect(rect,roundn ess);
pDC->SelectObject(pOldPen) ;
pDC->SelectObject(pOldBrus h);
// shrink interior so content doesn't leak
rect.DeflateRect(1,1);
#else
// set up flags for button style
DWORD flags = DFCS_ADJUSTRECT|DFCS_BUTTO NPUSH;
if (state & ODS_SELECTED) flags |= DFCS_PUSHED;
if (state & ODS_DISABLED) flags |= DFCS_INACTIVE;
// draw the button
pDC->DrawFrameControl(rect ,DFC_BUTTO N,flags);
// shrink intereior
rect.DeflateRect(1,1);
// offset down and right when pressed
if (state & ODS_SELECTED) rect.OffsetRect(1,1);
#endif
}
void CRoundRectButton::DrawText (CDC* pDC, const CRect& rect, LPCTSTR text, UINT state) {
// Draw the text transparently
int nBkModeOld = pDC->SetBkMode(TRANSPARENT );
COLORREF textcol = ::GetSysColor(COLOR_BTNTEX T);
COLORREF oldTextColor = pDC->SetTextColor(textcol) ;
// ensure it is centred in the button rect
CSize textSizeClient = pDC->GetTextExtent(text,st rlen(text) );
int x = rect.left+(rect.Width()-te xtSizeClie nt.cx)/2;
int y = rect.top+(rect.Height()-te xtSizeClie nt.cy)/2;
pDC->DrawState(
CPoint(x,y), rect.Size(), text,
(state & ODS_DISABLED?DSS_DISABLED: DSS_NORMAL ), true, 0, (HBRUSH)NULL
);
pDC->SetTextColor(oldTextC olor);
pDC->SetBkMode(nBkModeOld) ;
}
void CRoundRectButton::Draw(CDC * pDC, const CRect& inrect, UINT state) {
CRect rect = inrect;
DrawBorders(pDC,rect,state );
CPoint textpoint = rect.TopLeft();
CSize textsize = rect.Size();
CRect textrect(textpoint,textsiz e);
DrawText(pDC,textrect,text ,state);
}
void CRoundRectButton::PreSubcl assWindow( ) {
// ensure we are owner drawn
SetButtonStyle(GetButtonSt yle() | BS_OWNERDRAW);
}
void CRoundRectButton::DrawItem (LPDRAWITE MSTRUCT lpDIS) {
// call Draw to do the work
CDC* pDC = CDC::FromHandle(lpDIS->hDC );
ASSERT_VALID(pDC);
CRect rectClient = lpDIS->rcItem;
Draw(pDC,rectClient,lpDIS- >itemState );
}
void CRoundRectButton::DrawBord
#ifdef ROUND
// black border, white inside
CPen edgepen(PS_SOLID,0,RGB(0,0
CPen shadowpen(PS_SOLID,0,RGB(1
CPen facebrush(RGB(255,255,255)
CPen shadowbrush(RGB(128,128,12
CPen* pOldPen = pDC->SelectObject(&shadowp
CBrush* pOldBrush = pDC->SelectObject(&shadowb
// allow for shadow
rect.DeflateRect(1,1);
// setup roundness
CPoint roundness;
roundness.x = roundness.y = rect.Height()/2;
// draw shadow first
if (state & ODS_SELECTED) {
// draw shadow at topleft
rect.OffsetRect(0,0);
pDC->RoundRect(rect,roundn
rect.OffsetRect(1,1);
} else {
// draw shadow at bottom right
rect.OffsetRect(1,1);
pDC->RoundRect(rect,roundn
rect.OffsetRect(-1,-1);
}
// now draw the button over the top of the shadow
pDC->SelectObject(&facebru
pDC->SelectObject(&edgepen
pDC->RoundRect(rect,roundn
pDC->SelectObject(pOldPen)
pDC->SelectObject(pOldBrus
// shrink interior so content doesn't leak
rect.DeflateRect(1,1);
#else
// set up flags for button style
DWORD flags = DFCS_ADJUSTRECT|DFCS_BUTTO
if (state & ODS_SELECTED) flags |= DFCS_PUSHED;
if (state & ODS_DISABLED) flags |= DFCS_INACTIVE;
// draw the button
pDC->DrawFrameControl(rect
// shrink intereior
rect.DeflateRect(1,1);
// offset down and right when pressed
if (state & ODS_SELECTED) rect.OffsetRect(1,1);
#endif
}
void CRoundRectButton::DrawText
// Draw the text transparently
int nBkModeOld = pDC->SetBkMode(TRANSPARENT
COLORREF textcol = ::GetSysColor(COLOR_BTNTEX
COLORREF oldTextColor = pDC->SetTextColor(textcol)
// ensure it is centred in the button rect
CSize textSizeClient = pDC->GetTextExtent(text,st
int x = rect.left+(rect.Width()-te
int y = rect.top+(rect.Height()-te
pDC->DrawState(
CPoint(x,y), rect.Size(), text,
(state & ODS_DISABLED?DSS_DISABLED:
);
pDC->SetTextColor(oldTextC
pDC->SetBkMode(nBkModeOld)
}
void CRoundRectButton::Draw(CDC
CRect rect = inrect;
DrawBorders(pDC,rect,state
CPoint textpoint = rect.TopLeft();
CSize textsize = rect.Size();
CRect textrect(textpoint,textsiz
DrawText(pDC,textrect,text
}
void CRoundRectButton::PreSubcl
// ensure we are owner drawn
SetButtonStyle(GetButtonSt
}
void CRoundRectButton::DrawItem
// call Draw to do the work
CDC* pDC = CDC::FromHandle(lpDIS->hDC
ASSERT_VALID(pDC);
CRect rectClient = lpDIS->rcItem;
Draw(pDC,rectClient,lpDIS-
}
Change the DrawBorder function to draw the button differently (eg, change colours, roundness etc)
Also you can change the DrawText function so it uses DrawState to draw your bitmap (an icon is better though).
I also have code for drawing icons and/or text on a button, if you want.
Also you can change the DrawText function so it uses DrawState to draw your bitmap (an icon is better though).
I also have code for drawing icons and/or text on a button, if you want.
ASKER
RONSLOW,
Thanks for the sample. It sure looks like something I can start with. And yes, I would love to have ANY samples involving owner-draw buttons, bitmaps, icons, whatever.
Especially, "code for drawing icons and/or text on a button", although I've been able to draw a simple bitmap (it doesn't scale to the button size though) on a button. I suppose I need to do BitBlt or StretchBlt. I've re-read Prosise's Chapters (2,5)on Drawing, and Controls. Also, chapter 12: on Bitmaps and Regions. It's fun, but a whole lot of stuff to digest before I KNOW how to do this- or at least in the best way possible.
Thanks
Thanks for the sample. It sure looks like something I can start with. And yes, I would love to have ANY samples involving owner-draw buttons, bitmaps, icons, whatever.
Especially, "code for drawing icons and/or text on a button", although I've been able to draw a simple bitmap (it doesn't scale to the button size though) on a button. I suppose I need to do BitBlt or StretchBlt. I've re-read Prosise's Chapters (2,5)on Drawing, and Controls. Also, chapter 12: on Bitmaps and Regions. It's fun, but a whole lot of stuff to digest before I KNOW how to do this- or at least in the best way possible.
Thanks
ASKER
RONSLOW,
I think you need to lock this question again yourself (I've unlocked it) for me to give you any points.
Thui,
I appreciate your response, but the system doesn't allow me to divide the points. Thanks for your help.
I think you need to lock this question again yourself (I've unlocked it) for me to give you any points.
Thui,
I appreciate your response, but the system doesn't allow me to divide the points. Thanks for your help.
You can ask Linda to do a point split for you. Send her mail at Linda@experts-exchange.com (make sure you tell here the Q.xxxx number) and/or post a message in the Experts Exchange Customer Service topic area.
If you don't have any response in a day or two, then I'll come back here and answer. But it would be nice if you could share the points appropriately.
I've dug up an (old) version of my code for icon and/or text buttons and send it to you. Pelase see your inbox.
If you don't have any response in a day or two, then I'll come back here and answer. But it would be nice if you could share the points appropriately.
I've dug up an (old) version of my code for icon and/or text buttons and send it to you. Pelase see your inbox.
RONSLOW,
Please post an answer so you can receive points for all the work you've done. I'll post another question to give thui the points MuraliKrishna would like him to receive.
Linda Gardner
Customer Service @ Experts Exchange
Please post an answer so you can receive points for all the work you've done. I'll post another question to give thui the points MuraliKrishna would like him to receive.
Linda Gardner
Customer Service @ Experts Exchange
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.