• 使用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上去。

  • 相关阅读:
    开源软件的国内镜像
    ruby学习之路(一)
    VBS正则表达式
    fscanf和feof的组合使用
    计算机产生随机数
    常用:JQ
    unitegallery 测试使用-自动播放关闭
    H5重力感应(转)
    JS中,如何判断一个数是不是小数?如果是小数,如何判断它是几位小数 保留n位小数
    input禁止显示历史输入记录
  • 原文地址:https://www.cnblogs.com/tupx/p/3453524.html
Copyright © 2020-2023  润新知