Problem with a custom groupbox
Hello,
I have build a custom groupbox control, derived from a CButton. I have
used a MemDC to avoid flickering on resize but now the control isn't
painted as it should, there is a black margin (background) especially
in the corners where it should be rounded, a black border appears.
Here is the code:
// CustomGroupBox.cpp : implementation file
//
#include "stdafx.h"
#include "CustomGroupBox.h"
// CCustomGroupBox
IMPLEMENT_DYNAMIC(CCustomGroupBox, CButton)
CCustomGroupBox::CCustomGroupBox()
{
m_strTitle = _T("");
m_clrBorder = ::GetSysColor(COLOR_3DSHADOW);
m_clrClientBackground = ::GetSysColor(COLOR_BTNFACE);
m_captionBorder = RGB(47, 68, 89);
m_clrTitleText = ::GetSysColor(COLOR_WINDOWTEXT);
m_clrTitleBackground = ::GetSysColor(COLOR_BTNFACE);
m_nType = XPGB_FRAME;
m_dwAlignment = SS_LEFT;
containsIcon = false;
//bitmap.LoadBitmap(MAKEINTRESOURCE(IDB_S_ICON1));
}
CCustomGroupBox::~CCustomGroupBox()
{
}
BEGIN_MESSAGE_MAP(CCustomGroupBox, CButton)
ON_WM_PAINT()
ON_WM_ERASEBKGND( )
ON_WM_SIZE ()
END_MESSAGE_MAP()
BOOL CCustomGroupBox::OnEraseBkgnd(CDC* pDC)
{
//return CButton::OnEraseBkgnd(pDC);
return FALSE;
}
void CCustomGroupBox::OnSize(UINT,int,int)
{
//RedrawWindow();
}
void CCustomGroupBox::OnPaint()
{
//CBufferDC dc(this);
CPaintDC pDC(this);
CRect rectClient;
GetClientRect(rectClient);
CMemDC dc(&pDC);
/*CDC dc;
dc.CreateCompatibleDC(&pDC);
CBitmap bm;
bm.CreateCompatibleBitmap(&pDC,rectClient.Width(),rectClient.Height());
CBitmap *oldBitmap = dc.SelectObject(&bm);*/
// Defalte Rect
rectClient.DeflateRect(1,1);
// Get Text Rect
CSize sizeText;
CRect rectText, rectFrame;
CRect rectTitle, rectContent;
CFont *pOldFont = dc.SelectObject(&m_font);
// get Text if need
if ( m_strTitle.IsEmpty() )
{
GetWindowText(m_strTitle);
if ( ! m_strTitle.IsEmpty() )
m_strTitle = _T(" ") + m_strTitle + _T(" ");
}
if ( ! m_strTitle.IsEmpty() )
{
sizeText = dc.GetTextExtent(m_strTitle);
}
else
{
sizeText.cx = 0;
sizeText.cy = 0;
}
if ( m_nType == XPGB_FRAME ) // Frame style
{
// Calculate Text Rect
switch(m_dwAlignment)
{
case SS_LEFT:
rectText.top = rectClient.top;
rectText.left = rectClient.left + 10;
rectText.bottom = rectText.top + sizeText.cy;
rectText.right = rectText.left + sizeText.cx;
break;
case SS_CENTER:
rectText.top = rectClient.top;
rectText.left = rectClient.left + (rectClient.Width() -
sizeText.cx) / 2 ;
rectText.bottom = rectText.top + sizeText.cy;
rectText.right = rectText.left + sizeText.cx;
break;
case SS_RIGHT :
rectText.top = rectClient.top;
rectText.right = rectClient.right -10 ;
rectText.bottom = rectText.top + sizeText.cy;
rectText.left = rectText.right - sizeText.cx;
break;
}
// Calculate Frame rect
rectFrame.left = rectClient.left;
rectFrame.top = rectClient.top + sizeText.cy/2;
rectFrame.right = rectClient.right;
rectFrame.bottom = rectFrame.top + rectClient.Height() - sizeText.cy/
2;
// Draw Frame border
CPen penFrame;
CBrush brushBKFrame(m_clrTitleBackground);
penFrame.CreatePen(PS_SOLID, 1, m_clrBorder);
CPen* pOldPen = dc.SelectObject(&penFrame);
CBrush* pOldBrush = (CBrush*)dc.SelectStockObject(NULL_BRUSH);
dc.Rectangle(rectFrame);
dc.SelectObject(pOldPen);
dc.SelectObject(pOldBrush);
dc.IntersectClipRect(rectText);
dc.FillSolidRect(rectText, m_clrTitleBackground);
}
else{
// Calculate Title size
rectTitle.top = rectClient.top;
rectTitle.left = rectClient.left ;
rectTitle.right = rectClient.right;
rectTitle.bottom = rectClient.top + sizeText.cy + 4;
// Draw Title round rect
CPen penFrame;
CBrush brushBKTitle(m_clrTitleBackground);
CBrush brushBKContent(m_clrClientBackground);
//modifica aici
penFrame.CreatePen(PS_SOLID, 1, RGB(54, 66, 80));
CPen* pOldPen = dc.SelectObject(&penFrame);
CBrush* pOldBrush = dc.SelectObject(&brushBKTitle);
dc.RoundRect(rectClient, CPoint(10, 10));
dc.SelectObject(pOldBrush);
// Draw content area
rectContent.left = rectClient.left;
rectContent.top = rectClient.top + sizeText.cy + 20;
rectContent.right = rectClient.right;
rectContent.bottom = rectContent.top + rectClient.Height() -
sizeText.cy ;
pOldBrush = dc.SelectObject(&brushBKContent);
dc.Rectangle(rectContent);
dc.SelectObject(pOldPen);
dc.SelectObject(pOldBrush);
// Calculate Text Rect
switch(m_dwAlignment)
{
case SS_LEFT:
rectText.top = rectTitle.top + 10;
rectText.left = rectTitle.left + 2 ;
rectText.bottom = rectText.top + sizeText.cy;
rectText.right = rectText.left + sizeText.cx ;
break;
case SS_CENTER:
rectText.top = rectTitle.top + 2;
rectText.left = rectTitle.left + (rectTitle.Width() -
sizeText.cx) / 2 ;
rectText.bottom = rectText.top + sizeText.cy;
rectText.right = rectText.left + sizeText.cx ;
break;
case SS_RIGHT :
rectText.top = rectTitle.top + 2;
rectText.right = rectClient.right - 2 ;
rectText.bottom = rectText.top + sizeText.cy;
rectText.left = rectText.right - sizeText.cx;
break;
}
}
CRect iconRect;
/*CPen captionBorderPen;
captionBorderPen.CreatePen(PS_SOLID, 1, m_captionBorder);
dc.SelectObject(captionBorderPen);
dc.RoundRect(rectClient, CPoint(10, 10));*/
COLORREF clrOldText = dc.SetTextColor(m_clrTitleText);
UINT nMode = dc.SetBkMode(TRANSPARENT);
iconRect.top = rectText.top-5;
iconRect.left = rectText.left - 5;
iconRect.bottom = rectText.top + 35;
iconRect.right = rectText.left + 30;
if (containsIcon)
{
DrawIcon(&dc,iconRect);
}
rectText.left += 30;
dc.DrawText(m_strTitle, &rectText, DT_LEFT|DT_VCENTER|DT_SINGLELINE|
DT_NOCLIP ); //DT_END_ELLIPSIS);
//pDC.BitBlt(0, 0, rectContent.Width(),rectContent.Height(), &dc, 0,
0, SRCCOPY);
// restore DC
dc.SetBkMode(nMode);
dc.SetTextColor(clrOldText);
dc.SelectObject(pOldFont);
//dc.SelectObject(oldBitmap);
}
BOOL CCustomGroupBox::Create(LPCTSTR lpszClassName, LPCTSTR
lpszWindowName, DWORD dwStyle, const RECT &rect, CWnd *pParentWnd,
UINT nID, CCreateContext *pContext)
{
dwStyle |= BS_ICON;
return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect,
pParentWnd, nID, pContext);
}
BOOL CCustomGroupBox::PreCreateWindow(CREATESTRUCT &cs)
{
/*cs.style |= BS_ICON;
cs.style |= WS_CLIPSIBLINGS;
cs.style |= WS_CLIPCHILDREN;*/
return CButton::PreCreateWindow(cs);
}
void CCustomGroupBox::PreSubclassWindow()
{
CButton::PreSubclassWindow();
//modified the style to avoid text overlap when press tab
ModifyStyle(0, BS_ICON | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
// Get Defalut Font
CFont* cf = GetFont();
if(cf !=NULL)
{
cf->GetObject(sizeof(m_lf),&m_lf);
}
else
{
GetObject(GetStockObject(SYSTEM_FONT),sizeof(m_lf),&m_lf);
}
ReconstructFont();
}
void CCustomGroupBox::ReconstructFont()
{
m_font.DeleteObject();
BOOL bCreated = m_font.CreateFontIndirect(&m_lf);
}
void CCustomGroupBox::UpdateSurface()
{
CRect (rc);
GetWindowRect(rc);
RedrawWindow();
GetParent()->ScreenToClient(rc);
GetParent()->InvalidateRect(rc,TRUE);
GetParent()->UpdateWindow();
}
void CCustomGroupBox::SetXPGroupStyle(XPGroupBoxStyle eStyle)
{
m_nType = eStyle;
UpdateSurface();
}
void CCustomGroupBox::SetFont(LOGFONT lf)
{
CopyMemory(&m_lf, &lf, sizeof(m_lf));
ReconstructFont();
UpdateSurface();
}
void CCustomGroupBox::SetFontBold(BOOL bBold)
{
m_lf.lfWeight = bBold ? FW_BOLD : FW_NORMAL;
ReconstructFont();
UpdateSurface();
}
void CCustomGroupBox::SetFontName(const CString &strFont, BYTE
byCharSet)
{
m_lf.lfCharSet = byCharSet;
_tcscpy(m_lf.lfFaceName,strFont);
ReconstructFont();
UpdateSurface();
}
void CCustomGroupBox::SetFontUnderline(BOOL bSet)
{
m_lf.lfUnderline = bSet;
ReconstructFont();
UpdateSurface();
}
void CCustomGroupBox::SetFontItalic(BOOL bSet)
{
m_lf.lfItalic = bSet;
ReconstructFont();
UpdateSurface();
}
void CCustomGroupBox::SetFontSize(int nSize)
{
CFont cf;
LOGFONT lf;
cf.CreatePointFont(nSize * 10, m_lf.lfFaceName);
cf.GetLogFont(&lf);
m_lf.lfHeight = lf.lfHeight;
m_lf.lfWidth = lf.lfWidth;
ReconstructFont();
UpdateSurface();
}
void CCustomGroupBox::SetBorderColor(COLORREF clrBorder)
{
m_clrBorder = clrBorder;
UpdateSurface();
}
void CCustomGroupBox::SetCatptionTextColor(COLORREF clrText)
{
m_clrTitleText = clrText;
UpdateSurface();
}
void CCustomGroupBox::SetBackgroundColor(COLORREF clrBKClient)
{
m_clrTitleBackground = clrBKClient;
m_clrClientBackground = clrBKClient;
UpdateSurface();
}
void CCustomGroupBox::SetBackgroundColor(COLORREF clrBKTilte, COLORREF
clrBKClient)
{
m_clrTitleBackground = clrBKTilte;
m_clrClientBackground = clrBKClient;
UpdateSurface();
}
void CCustomGroupBox::SetText(LPCTSTR lpszText)
{
if(IsWindow(this->GetSafeHwnd()))
{
m_strTitle = lpszText;
m_strTitle = _T(" ") + m_strTitle + _T(" ");
UpdateSurface();
}
}
void CCustomGroupBox::SetAlignment(DWORD dwType)
{
switch(dwType)
{
default : ASSERT(false);
case SS_LEFT:
m_dwAlignment = SS_LEFT;
break;
case SS_CENTER:
m_dwAlignment = SS_CENTER;
break;
case SS_RIGHT :
m_dwAlignment = SS_RIGHT;
break;
}
UpdateSurface();
}
void CCustomGroupBox::DrawBitmap(CRect rect)
{
CDC *pDC = GetDC();
CDC *memDC = new CDC();
memDC->CreateCompatibleDC(pDC);
memDC->SelectObject(bitmap);
pDC->BitBlt(2, 3, rect.Width(), rect.Height(), memDC, 0, 0, SRCCOPY);
}
void CCustomGroupBox::DrawIcon(CDC* pDC,CRect iconRect)
{
CBitmap *icon = new CBitmap();
icon->LoadBitmapW(MAKEINTRESOURCE(iconResource));
//CDC *pDC = GetDC();
CDC *memDC = new CDC();
memDC->CreateCompatibleDC(pDC);
memDC->SelectObject(icon);
pDC->BitBlt(4, 4, iconRect.Width(), iconRect.Height(), memDC, 0, 0,
SRCCOPY);
}
void CCustomGroupBox::SetIcon(int iconRes)
{
containsIcon = true;
iconResource = iconRes;
}