• 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

           

              

  • 相关阅读:
    递归要记得返回
    git push的时候报Unable to find remote helper for 'https'的错误
    iphone手机上的click和touch事件
    对jquery的conflict方法的解读
    开发富文本编辑器的一些体会
    使用jquery制作动态加载型菜单
    解决jquery$命名符和其它框架的冲突问题
    基于geolocation来获取经纬度地址
    Python学习笔记2解析数据
    Python学习笔记1数据类型
  • 原文地址:https://www.cnblogs.com/small-lazybee/p/10401791.html
Copyright © 2020-2023  润新知