Discussion:
Owner-Draw Round Button
(too old to reply)
sawer
2009-07-19 08:56:01 UTC
Permalink
Hi

I'm tring to make owner draw round button.

1-)void CMyButton::PreSubclassWindow()
{
CRect rc;
GetClientRect( &rc );
CRgn Region;
Region.CreateRoundRectRgn(rc.left,rc.top,rc.right,rc.bottom,50,50);
SetWindowRgn(Region,TRUE);


CButton::PreSubclassWindow();
}
I searched and find out that SetWindowrgn function is used in
PreSubclassWindow handler. Is that a choice or rule for owner drawing?

2-) If i set owner-darw button to TRUE, i must write DrawItem method of my
custom class. I tried this:
void CMyButton::DrawItem(LPDRAWITEMSTRUCT dis)
{

CDC * dc = CDC::FromHandle(dis->hDC);
CRect r;
GetClientRect(&r);

int save = dc->SaveDC();

COLORREF color;
color = dis->itemState & ODS_SELECTED ? RGB(0,255,0) : RGB(255, 0, 0);
CBrush br(color);
dc->SelectObject(&br);

dc->SelectClipPath(RGN_COPY);

dc->PatBlt(0, 0, r.Width(), r.Height(), PATCOPY);

dc->StrokePath();

dc->RestoreDC(save);

}
But it didn't draw round button. What must be written to DrawItem function?

Thanks.
sawer
2009-07-19 13:51:01 UTC
Permalink
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItem)
{

CDC* pDC = CDC::FromHandle(lpDrawItem->hDC);
CRect rect = lpDrawItem->rcItem;

pDC->SelectStockObject(NULL_BRUSH);
pDC->FillSolidRect(rect, RGB(255,0,0));
}

void CMyButton::PreSubclassWindow()
{
CRect rc;
GetClientRect( &rc );
CRgn Region;
Region.CreateRoundRectRgn(rc.left,rc.top,rc.right,rc.bottom,50,50);
SetWindowRgn(Region,TRUE);


CButton::PreSubclassWindow();
}

I don't understand.
Calling SetWindowRgn is not enough?
I'm calling SetWindowRgn but it still draw rectangle when calling
FillSolidRect?

I don't figure out how DrawItem must be?
msnews.microsoft.com
2009-07-19 14:36:28 UTC
Permalink
Why don't you want to use Region Functions (FillRgn) instead?

Victor
Post by sawer
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItem)
{
CDC* pDC = CDC::FromHandle(lpDrawItem->hDC);
CRect rect = lpDrawItem->rcItem;
pDC->SelectStockObject(NULL_BRUSH);
pDC->FillSolidRect(rect, RGB(255,0,0));
}
void CMyButton::PreSubclassWindow()
{
CRect rc;
GetClientRect( &rc );
CRgn Region;
Region.CreateRoundRectRgn(rc.left,rc.top,rc.right,rc.bottom,50,50);
SetWindowRgn(Region,TRUE);
CButton::PreSubclassWindow();
}
I don't understand.
Calling SetWindowRgn is not enough?
I'm calling SetWindowRgn but it still draw rectangle when calling
FillSolidRect?
I don't figure out how DrawItem must be?
sawer
2009-07-19 15:16:01 UTC
Permalink
If i call setwindowrgn, and then draw rectangle or draw a bigger size than
button control, i expected to see round image. Because i call setwindowrgn.
But it is not. It is confused me

I mean as you said. This works. It shows round button:
CRgn Region;
Region.CreateRoundRectRgn(rc.left,rc.top,rc.right,rc.bottom,100,100);
CBrush br;
br.CreateSolidBrush(RGB(255,0,0));
pDC->FillRgn(&Region, &br);

but if i replace FillRgn with FillsolidRectangle

pDC->FillSolidRect(rc, RGB(255,0,0));

draws rectangle. But i called setwindowrgn. Why does it still draw rectangle?

Thanks
Post by msnews.microsoft.com
Why don't you want to use Region Functions (FillRgn) instead?
Victor
Post by sawer
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItem)
{
CDC* pDC = CDC::FromHandle(lpDrawItem->hDC);
CRect rect = lpDrawItem->rcItem;
pDC->SelectStockObject(NULL_BRUSH);
pDC->FillSolidRect(rect, RGB(255,0,0));
}
void CMyButton::PreSubclassWindow()
{
CRect rc;
GetClientRect( &rc );
CRgn Region;
Region.CreateRoundRectRgn(rc.left,rc.top,rc.right,rc.bottom,50,50);
SetWindowRgn(Region,TRUE);
CButton::PreSubclassWindow();
}
I don't understand.
Calling SetWindowRgn is not enough?
I'm calling SetWindowRgn but it still draw rectangle when calling
FillSolidRect?
I don't figure out how DrawItem must be?
David Ching
2009-07-19 17:55:18 UTC
Permalink
Post by sawer
void CMyButton::PreSubclassWindow()
{
CRect rc;
GetClientRect( &rc );
CRgn Region;
Region.CreateRoundRectRgn(rc.left,rc.top,rc.right,rc.bottom,50,50);
SetWindowRgn(Region,TRUE);
The problem is your Region is going out of scope and being destroyed. The
doc to SetWindowRgn says Windows will own the region you pass to it, and you
must not destroy it. You can fix it by calling instead:

SetWindowRgn(Region.Detach(),TRUE);


-- David
sawer
2009-07-19 18:58:00 UTC
Permalink
Thank you.

I just want to understand what SetWindowRgn effects?
For example in that picture
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=5620&lngWId=3


SetWindowRgn cuts top corners. Right?

But if i call pDC->FillSolidRect(rc, RGB(255,0,0));,
there is a red rectangle on the dialog box.

Why doesn't SetwindowRgn cut top corners like it does in the link, above?
David Ching
2009-07-20 03:53:22 UTC
Permalink
Post by sawer
Thank you.
I just want to understand what SetWindowRgn effects?
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=5620&lngWId=3
SetWindowRgn cuts top corners. Right?
Yes.
Post by sawer
But if i call pDC->FillSolidRect(rc, RGB(255,0,0));,
there is a red rectangle on the dialog box.
Why doesn't SetwindowRgn cut top corners like it does in the link, above?
Because your region is being destroye prematurely.


-- David
sawer
2009-07-20 07:54:00 UTC
Permalink
No I called Detach, but it doesn't change.

I added button click handler shows MessageBox. When i click top corners whic
I expect to be cut, doen't show Messagebox. It meaans it shows rectangle
button but top corners isn't involved.

So can we say , if we draw rectangle in DrawItem, it overrides SetWindowRgn
which is called in PreSubclassWindow?
Post by David Ching
Post by sawer
Thank you.
I just want to understand what SetWindowRgn effects?
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=5620&lngWId=3
SetWindowRgn cuts top corners. Right?
Yes.
Post by sawer
But if i call pDC->FillSolidRect(rc, RGB(255,0,0));,
there is a red rectangle on the dialog box.
Why doesn't SetwindowRgn cut top corners like it does in the link, above?
Because your region is being destroye prematurely.
-- David
David Ching
2009-07-20 14:31:42 UTC
Permalink
Post by sawer
No I called Detach, but it doesn't change.
I added button click handler shows MessageBox. When i click top corners whic
I expect to be cut, doen't show Messagebox. It meaans it shows rectangle
button but top corners isn't involved.
So can we say , if we draw rectangle in DrawItem, it overrides
SetWindowRgn
which is called in PreSubclassWindow?
Well, I've not used SetWindowRgn on a child window before. So when in
doubt, google. ;)
http://www.codeproject.com/KB/buttons/irregular_buttons.aspx

Cheers,
David
Joseph M. Newcomer
2009-07-20 14:44:34 UTC
Permalink
I did letter-shaped buttons in my SetWindowRgn example. Take a look at the code in my
example, on my MVP Tips site.
joe
Post by sawer
No I called Detach, but it doesn't change.
I added button click handler shows MessageBox. When i click top corners whic
I expect to be cut, doen't show Messagebox. It meaans it shows rectangle
button but top corners isn't involved.
So can we say , if we draw rectangle in DrawItem, it overrides SetWindowRgn
which is called in PreSubclassWindow?
Post by David Ching
Post by sawer
Thank you.
I just want to understand what SetWindowRgn effects?
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=5620&lngWId=3
SetWindowRgn cuts top corners. Right?
Yes.
Post by sawer
But if i call pDC->FillSolidRect(rc, RGB(255,0,0));,
there is a red rectangle on the dialog box.
Why doesn't SetwindowRgn cut top corners like it does in the link, above?
Because your region is being destroye prematurely.
-- David
Joseph M. Newcomer [MVP]
email: ***@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Joseph M. Newcomer
2009-07-20 14:43:14 UTC
Permalink
CreateEllipticRgn?

You did not describe what you DID see...perhaps you saw a button in the shape of a rounded
rectangle...
joe
Post by sawer
Hi
I'm tring to make owner draw round button.
1-)void CMyButton::PreSubclassWindow()
{
CRect rc;
GetClientRect( &rc );
CRgn Region;
Region.CreateRoundRectRgn(rc.left,rc.top,rc.right,rc.bottom,50,50);
SetWindowRgn(Region,TRUE);
CButton::PreSubclassWindow();
}
I searched and find out that SetWindowrgn function is used in
PreSubclassWindow handler. Is that a choice or rule for owner drawing?
2-) If i set owner-darw button to TRUE, i must write DrawItem method of my
void CMyButton::DrawItem(LPDRAWITEMSTRUCT dis)
{
CDC * dc = CDC::FromHandle(dis->hDC);
CRect r;
GetClientRect(&r);
int save = dc->SaveDC();
COLORREF color;
color = dis->itemState & ODS_SELECTED ? RGB(0,255,0) : RGB(255, 0, 0);
CBrush br(color);
dc->SelectObject(&br);
dc->SelectClipPath(RGN_COPY);
dc->PatBlt(0, 0, r.Width(), r.Height(), PATCOPY);
dc->StrokePath();
dc->RestoreDC(save);
}
But it didn't draw round button. What must be written to DrawItem function?
Thanks.
Joseph M. Newcomer [MVP]
email: ***@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
sawer
2009-07-20 16:26:01 UTC
Permalink
I am just trying to understand why this simple code isn't working:

void CMyButton::PreSubclassWindow()
{
CRect rect;
GetClientRect(&rect);
CRgn rgn;
rgn.CreateEllipticRgnIndirect(&rect);
SetWindowRgn(rgn, TRUE);
rgn.Detach();
CButton::PreSubclassWindow();
}

void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rect = lpDrawItemStruct->rcItem;
pDC->FillSolidRect(&rect, RGB(255,0,0));
}

I made an elliptic region in PreSubclassWindow() and then called to
FillSolidRect().

Why is there a rectangle button? Why are top corners seen?
Thanks.
Joseph M. Newcomer
2009-07-20 17:22:22 UTC
Permalink
Take a look at what I did for the "CAT" buttons in my SetWindowRgn example; they are
owner-draw buttons. I may have done clipping.
joe
Post by sawer
void CMyButton::PreSubclassWindow()
{
CRect rect;
GetClientRect(&rect);
CRgn rgn;
rgn.CreateEllipticRgnIndirect(&rect);
SetWindowRgn(rgn, TRUE);
rgn.Detach();
CButton::PreSubclassWindow();
}
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rect = lpDrawItemStruct->rcItem;
pDC->FillSolidRect(&rect, RGB(255,0,0));
}
I made an elliptic region in PreSubclassWindow() and then called to
FillSolidRect().
Why is there a rectangle button? Why are top corners seen?
Thanks.
Joseph M. Newcomer [MVP]
email: ***@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
sawer
2009-07-20 18:08:02 UTC
Permalink
Yes you did. So your program didn't allow to paint. There is a round button.

//This is OK.
CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rect = lpDrawItemStruct->rcItem;
CRgn rgn;
rgn.CreateEllipticRgnIndirect(&rect);
//If I doesn't call SelectClipRgn there is a rectangle
button
pDC->SelectClipRgn(&rgn);
pDC->FillSolidRect(&rect, RGB(255,0,0));


But in MSDN, it writes:
"The window region determines the area within the window where the system
permits drawing. The system does not display any portion of a window that
lies outside of the window region "

So can we say this is not completly right?
Because if someone sets region of a window but doesn't make clipping, system
still displays outside of the window region.
Post by Joseph M. Newcomer
Take a look at what I did for the "CAT" buttons in my SetWindowRgn example; they are
owner-draw buttons. I may have done clipping.
joe
Post by sawer
void CMyButton::PreSubclassWindow()
{
CRect rect;
GetClientRect(&rect);
CRgn rgn;
rgn.CreateEllipticRgnIndirect(&rect);
SetWindowRgn(rgn, TRUE);
rgn.Detach();
CButton::PreSubclassWindow();
}
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rect = lpDrawItemStruct->rcItem;
pDC->FillSolidRect(&rect, RGB(255,0,0));
}
I made an elliptic region in PreSubclassWindow() and then called to
FillSolidRect().
Why is there a rectangle button? Why are top corners seen?
Thanks.
Joseph M. Newcomer [MVP]
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
David Ching
2009-07-20 21:11:16 UTC
Permalink
Post by sawer
Because if someone sets region of a window but doesn't make clipping, system
still displays outside of the window region.
For sure, if you SetWindowRgn a WS_POPUP window, then do a FillSolidRect()
on it, it will fill only the region and not the entire rect. I don't know
why it doesn't work in an Owner Draw button.

-- David

Loading...