使用Gdi+绘制圆角矩形(CTabCtrl控件记录一)

所在项目中的定位是一个外观为圆角矩形的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上去。

原文地址:https://www.cnblogs.com/tupx/p/3453524.html