VC使用双缓冲制作绘图控件

       

         最近用VC做了一个画图的控件。控件在使用的时候遇到点问题。在控件里画了图之后切换到其他页面,等再切换回来的时候,发现控件里画的图都不见了。这是因为VC里面,当缩小、遮挡页面后客户区域就会失效,当再次显示的时候系统就自动调用OnDraw 函数进行重绘。所以原来保存的图形都消失了。由于我做的是控件,所以不可能用一般的方法来解决比如在OnDraw 函数里绘图。经过这种查找决定使用双缓冲绘图来解决这个问题。

       普通的绘图是直接将图像绘制到设备上,双缓冲绘图是将图形绘制到内存的一张图片上,等所有的绘图完成后再将整幅图片显示在设备上(个人的理解可能 不太准确)。所以这里我们可以将图片设为成员变量。各绘图函数都在该图片上绘图。并且在OnDraw 函数里显示这幅图片,这样就可以在页面切换回来的时候显示以前画的图了。

 

  代码如下:

 

  文件DrawShapeCtrl.h 中: 

class CDrawShapeCtrl : public COleControl
{
........
private: CBitmap m_Bitmap; //CDC m_dcMem;//切记不能这样定义 BOOL m_bFisrtTime;//第一次加载 BOOL m_bClear; };

 

DrawShapeCtrl.cpp 中:

CDrawShapeCtrl::CDrawShapeCtrl()
{
    InitializeIIDs(&IID_DDrawShape, &IID_DDrawShapeEvents);
    // TODO: Initialize your control's instance data here.
    m_bFisrtTime = TRUE;
    m_bClear = FALSE;
    
}

OnDraw 函数中:

void CDrawShapeCtrl::OnDraw(
            CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
    if (!pdc)
        return;

    //// TODO: Replace the following code with your own drawing code.

    CRect rect;
    GetClientRect(&rect);
    
    CDC  dcMem;
    dcMem.CreateCompatibleDC(pdc);
    

    //first time
    if (m_bFisrtTime)
    {
        
        m_Bitmap.CreateCompatibleBitmap(pdc,rect.Width(),rect.Height());
        dcMem.SelectObject(&m_Bitmap);

        //填充为白色
        dcMem.FillSolidRect(0,0,rect.Width(),rect.Height(),RGB(255,255,255));

        //画坐标轴
        CPen             pen;
        CPen*            pOldPen;
        pen.CreatePen( PS_DOT, 1, RGB(120,120,120));
        pOldPen = dcMem.SelectObject( &pen );

        dcMem.MoveTo(rect.left,rect.Height()/2);
        dcMem.LineTo(rect.right,rect.Height()/2);
        dcMem.MoveTo(rect.Width()/2,rect.top);
        dcMem.LineTo(rect.Width()/2,rect.bottom); 

        dcMem.SelectObject(pOldPen);
        pOldPen->DeleteObject();

        m_bFisrtTime = FALSE;

    }

    dcMem.SelectObject(&m_Bitmap);
    if (m_bClear)
    {
        
        //填充为白色
        dcMem.FillSolidRect(0,0,rect.Width(),rect.Height(),RGB(255,255,255));

        //画坐标轴
        CPen             pen;
        CPen*            pOldPen;
        pen.CreatePen( PS_DOT, 1, RGB(120,120,120));
        pOldPen = dcMem.SelectObject( &pen );        

        dcMem.MoveTo(rect.left,rect.Height()/2);
        dcMem.LineTo(rect.right,rect.Height()/2);
        dcMem.MoveTo(rect.Width()/2,rect.top);
        dcMem.LineTo(rect.Width()/2,rect.bottom); 

        dcMem.SelectObject(pOldPen);
        pOldPen->DeleteObject();

        m_bClear = FALSE;
    }

    //显示
    pdc->BitBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,SRCCOPY);
    dcMem.DeleteDC();
    
}

 

画线的函数:

//Lstype--penstyle 线型 Lwidth --线宽度    color--颜色
void CDrawShapeCtrl::Line(LONG x1, LONG y1, LONG x2, LONG y2,LONG Lstyle,LONG Lwidth,OLE_COLOR color)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    // TODO: Add your dispatch handler code here

    CDC *pdc = GetDC();

    CRect rcClient;
    GetClientRect(rcClient);
    CDC memDC;
    memDC.CreateCompatibleDC(pdc);
    memDC.SelectObject(&m_Bitmap);


    // Change map mode, positive x right, positive y up.
    int nOldMode = memDC.SaveDC();
    memDC.SetMapMode(MM_ISOTROPIC);
    memDC.SetViewportExt(1, 1);
    memDC.SetWindowExt(1, -1);
    memDC.SetViewportOrg(rcClient.Width() / 2, rcClient.Height()/2);

    //设置画笔线型  宽度 颜色
    LOGBRUSH    logBrush;   
    logBrush.lbStyle    =    BS_SOLID;   
    logBrush.lbColor    =    color; 
    if (Lstyle<0||Lstyle>4)
    {
        return;
    }
    CPen Pen(Lstyle|PS_GEOMETRIC|PS_ENDCAP_ROUND, Lwidth,&logBrush);
    memDC.SelectObject(&Pen);

    //画线
    memDC.MoveTo(x1,y1);
    memDC.LineTo(x2,y2);

    // We must restore mapping mode before copy bitmap to client context.
    memDC.RestoreDC(nOldMode);

    // Copy double buffer bitmap to client context.
    pdc->BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &memDC, 0, 0, SRCCOPY);

    ReleaseDC(pdc);
    memDC.DeleteDC();
}

 

 

清空控件内的图形:

void CDrawShapeCtrl::Clear(void)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    // TODO: Add your dispatch handler code here
    m_bClear = TRUE;

    Invalidate(TRUE);
}

    在使用的过程当中发现,CDC 不能定义为全局的必须定义为局部变量,用完随即释放。否则第一次能画出图形,第二次调用的时候什么也画不出来。原因参考 

VC CDC类的使用 详解   

VC 绘图,使用双缓冲技术实现

https://wenku.baidu.com/view/2c6aaf1ba8114431b90dd862.html

参考:

https://blog.csdn.net/imletterh/article/details/46372753

 

 

       

          

转载于:https://www.cnblogs.com/small-lazybee/p/10401791.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值