所在项目中的定位是一个外观为圆角矩形的TabBtn控件,绘制圆角矩形部分的实现:
void CTabBtn::DoPaint(CDCHandle dc)//继承了CDoubleBufferImpl { Graphics graphics(dc); DrawTabBtn(&graphics); }
void CTabBtn::DrawTabBtn(Graphics* graphics) { RECT rect; ::GetClientRect(m_hWnd, &rect); int nItemCount = m_arrItems.size(); int nItemWidth = (rect.right - rect.left) / nItemCount; int nItemHeight = rect.bottom - rect.top; //draw background RectF oRect; if(m_bmpBkgnd == NULL) { //draw RoundRect background oRect.X = 0; oRect.Y = 0; oRect.Width = rect.right - rect.left; oRect.Height = nItemHeight; //APen = new Pen(BorderColor, (REAL)PenWidth); //ABrush = new LinearGradientBrush(GRect, FromColor, ToColor, LinearGradientModeVertical); DrawRoundRect(graphics, NULL, NULL, oRect, 10); } else { //HOW to clip the Round Rect area to draw image? //TextureBrush ? graphics->DrawImage(m_bmpBkgnd, oRect); } //begin to draw Tab Btns for(size_t i = 0; i < nItemCount; i++) { oRect.X = i * nItemWidth; //icon covers abt one forth place oRect.Y = 0; oRect.Width = nItemWidth * 1.0 / 3 ; oRect.Height = nItemHeight; if(m_arrItems[i]->icoNormal == NULL || m_arrItems[i]->icoOver == NULL || m_arrItems[i]->icoDown == NULL) { } else { if(m_arrItems[i]->bDown) { graphics->DrawImage(m_arrItems[i]->icoDown, oRect); oRect.X += nItemWidth * 1.0 / 4; oRect.Width = nItemWidth * 1.0 / 4 * 3; //icon covers 1/4 place DrawTabBtnTitle(graphics, m_arrItems[i]->title.c_str(), m_arrItems[i]->clrDown, oRect); //if not the last item, then draw a gradient vertical line //... } else if(m_arrItems[i]->bOver) { graphics->DrawImage(m_arrItems[i]->icoOver, oRect); oRect.X += nItemWidth * 1.0 / 4; oRect.Width = nItemWidth * 1.0 / 4 * 3; DrawTabBtnTitle(graphics, m_arrItems[i]->title.c_str(), m_arrItems[i]->clrOver, oRect); } else { graphics->DrawImage(m_arrItems[i]->icoNormal, oRect); oRect.X += nItemWidth * 1.0 / 4; oRect.Width = nItemWidth * 1.0 / 4 * 3 -5; DrawTabBtnTitle(graphics, m_arrItems[i]->title.c_str(), m_arrItems[i]->clrNormal, oRect); } }//draw TTabBtnItem //if not the last item, then draw the vertical line if(i != m_arrItems.size() - 1) { DrawGradientLine(graphics, (i+1) * nItemWidth-3 , oRect.Y, (i+1)*nItemWidth-3, oRect.Y+oRect.Height, NULL, NULL); }//draw the gradient vertical line }//traverse all items }
void CTabBtn::DrawRoundRect(Graphics* g, Pen* pen, Brush* brush, RectF rect, int nCornerRadius) { ATLASSERT(g != NULL); ATLASSERT(&rect != NULL); if(pen == NULL) pen = new Pen(Color::DimGray); if(brush == NULL) brush = new LinearGradientBrush(rect, Color::Gainsboro, Color::Gray, LinearGradientModeVertical); GraphicsPath* pRRPath = CreateRoundRectPath(rect, nCornerRadius); g->DrawPath(pen, pRRPath); g->FillPath(brush, pRRPath); }
GraphicsPath* CTabBtn::CreateRoundRectPath(RectF& oRect, int nCornerRadius) { if(nCornerRadius > oRect.Width || nCornerRadius > oRect.Height) return NULL; GraphicsPath* path = new GraphicsPath; path->StartFigure(); path->AddArc((REAL)oRect.X, (REAL)oRect.Y, (REAL)nCornerRadius*2, (REAL)nCornerRadius*2, 180.0, 90.0); //path->AddLine(oRect.X+nCornerRadius, oRect.Y, oRect.X+oRect.Width-nCornerRadius*2, oRect.Y);//not necessary for draw profile but if fill maybe must(didn't test) path->AddArc((REAL)oRect.X+oRect.Width-nCornerRadius*2, (REAL)oRect.Y, (REAL)nCornerRadius*2, (REAL)nCornerRadius*2, 270.0, 90.0); //path->AddLine(oRect.X+oRect.Width, oRect.Y+nCornerRadius*2, oRect.X+oRect.Width, oRect.Y+oRect.Height-nCornerRadius*2); path->AddArc((REAL)oRect.X+oRect.Width-nCornerRadius*2, (REAL)oRect.Y+oRect.Height-nCornerRadius*2, (REAL)nCornerRadius*2, (REAL)nCornerRadius*2, 0.0, 90.0); //path->AddLine(oRect.X+oRect.Width-nCornerRadius*2, oRect.Y+oRect.Height, oRect.X+nCornerRadius*2, oRect.Y+oRect.Height); path->AddArc((REAL)oRect.X, (REAL)oRect.Y+oRect.Height-nCornerRadius*2, (REAL)nCornerRadius*2, (REAL)nCornerRadius*2, 90.0, 90.0); //path->AddLine(oRect.X, oRect.Y+oRect.Height-nCornerRadius*2, oRect.X, oRect.Y+nCornerRadius*2); path->CloseFigure(); return path; }
这样绘制出来的效果有瑕疵,圆角部分的颜色与父窗口的颜色存在不一致的情况。后来摒弃了这种方法,采用直接绘制矩形,然后SetWindowRgn的方法,更简单且有效。
抽出时间,把相关代码添加到Git上去。