我想做一个类似Windows画图,但功能简单的多的小程序,这个程序在鼠标移动时画下鼠标移动的痕迹,想用双缓冲绘图。
在OnMouseMove中将图画到内存DC,OnDraw中将内存DC上画的图拷到屏幕上,这是我OnMouseMove中的代码:
CDC memDC; CRect rect;
CDC *pDC;

// 获取绘制坐标的文本框
CWnd* pWnd = GetDlgItem(IDC_STC_PIC);

pWnd->GetClientRect(&rect);
// 指针
pDC = pWnd->GetDC();
pWnd->Invalidate();
pWnd->UpdateWindow();
if((point.x>=Startx)&&(point.x<Startx+wid)&&(point.y>=Starty)
&&(point.y<Starty+lon))
{
HCURSOR m_HCross;
m_HCross=AfxGetApp()->LoadCursor(IDC_CURSOR1);
SetCursor(m_HCross);
} if((mouseDown==1)&&(point.x>=Startx)&&(point.x<Startx+wid)
&&(point.y>=Starty)&&(point.y<Starty+lon))
{
//内存绘图
CPen pen;
pen.CreatePen(PS_SOLID, 10, RGB (0, 0 , 0));
memDC.CreateCompatibleDC(pDC);
CPen* pOldPen = memDC.SelectObject (&pen);
pOldPen = memDC.SelectObject(&pen);
memDC.MoveTo(m_cpOldPoint);
memDC.LineTo(point); memDC.BitBlt(Startx,Starty,Startx+wid,Starty+lon, pDC,0,0,SRCCOPY);
pDC->BitBlt(rect.left,rect.top,rect.right,rect.bottom,&memDC,0,0,SRCCOPY);
m_cpOldPoint.x = point.x;
m_cpOldPoint.y = point.y;

memDC.SelectObject(pOldPen);
memDC.DeleteDC();
}
实际上,我在OnMouseMove中调用了BitBlt,想试试能不能画出来,但是失败了,请高人指点,不胜感激!

解决方案 »

  1.   

    1 内存DC应该选入一个位图做画布
    2 应该把目标DC的拷贝到内存DC,绘制操作,绘制完毕后 再拷贝回目标DC
    3 注意BitBlt的参数(int x, int y, int nWidth, int nHeight
    4 建议鼠标移动到处理中记录需要绘制的点 在WM_PAINT响应中绘制,否则重新刷新后什么也没有了
      

  2.   

    To zgl7903:
    非常感谢~~~~~~~~我先试试。
    “4 建议鼠标移动到处理中记录需要绘制的点 在WM_PAINT响应中绘制,否则重新刷新后什么也没有了”
    这个意思是说BitBlt在WM_PAINT响应中调用吗,还是整个的绘制过程在WM_PAINT响应中调用啊?
      

  3.   

    如果你希望在鼠标拖动的时候实时显示,那么在鼠标处理事件中也要GetDC然后双缓冲绘图,给你一个例子更直观void CSkf_MapView::OnDraw(CDC* pDC)
    {
    CSkf_MapDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    GetClientRect(&rect);      //获取当前客户区域的大小
    //在内存中开辟一块与当前DC相同的DC然后在其上作图
    CDC mDC;
    mDC.CreateCompatibleDC(pDC);
    CBitmap MemBitmap;
    MemBitmap.CreateCompatibleBitmap(pDC,rect.right ,rect.bottom );
    CBitmap *pOldBitmap=mDC.SelectObject(&MemBitmap);
    //改变背景颜色
    CBrush Brush_Bak(BKColor);  
    CBrush *pOldBrush=mDC.SelectObject(&Brush_Bak);
        mDC.SelectObject(Brush_Bak);
        mDC.FillRect(&rect,&Brush_Bak); 
        mDC.SelectObject(pOldBrush);
    //在以下绘图函数调用中,语句的先后决定了图层的先后,即先绘的在最下层。
    for (int i=0;i<3;i++)
    SKFDrawMap(&mDC,i);
        SKFDrawBitmap(&mDC,rect.right-190,rect.bottom-528,IDB_BMPME);
    SKFDrawText(&mDC);
    SKFDrawYellowriver(&mDC);
    SKFDrawChinese(&mDC);
    //将内存DC上所绘内容一次性拷贝到当前DC
    pDC->BitBlt(0,0,rect.right ,rect.bottom ,&mDC,0,0,SRCCOPY);

    }
      

  4.   

    To zgl7903:
    我把绘图的代码放到OnPaint的else中了:
    if (IsIconic())
    {
    ......
    }
    else
    {
    //在这里绘图
    //OnDraw(&dc); CDC memDC;
    CRect rect;
    CDC *pDC;
    CBitmap memBitmap;
    CBitmap* pOldBmp = NULL;

    // 获取绘制坐标的文本框
    CWnd* pWnd = GetDlgItem(IDC_STC_PIC);

    pWnd->GetClientRect(&rect);
    // 指针
    pDC = pWnd->GetDC();
    pWnd->Invalidate();
    pWnd->UpdateWindow();

    memDC.CreateCompatibleDC(pDC);               
    memBitmap.CreateCompatibleBitmap(pDC,rect.right,rect.bottom);
    pOldBmp = memDC.SelectObject(&memBitmap);
    memDC.BitBlt(rect.left,rect.top,rect.right,rect.bottom,pDC,0,0,SRCCOPY);

    if((mouseDown==1))
    {
    //内存绘图
    CPen pen;
    pen.CreatePen(PS_SOLID, 10, RGB (0, 0 , 0));
    CPen* pOldPen = memDC.SelectObject (&pen);
    pOldPen = memDC.SelectObject(&pen);
    memDC.MoveTo(m_cpOldPoint);
    memDC.LineTo(m_cpNewPoint);
    m_cpOldPoint.x = m_cpNewPoint.x;
    m_cpOldPoint.y = m_cpNewPoint.y;
    memDC.SelectObject(pOldPen);
    }
    //把内存绘图拷贝到屏幕
    pDC->BitBlt(rect.left,rect.top,rect.right,rect.bottom,&memDC,0,0,SRCCOPY); 
    memDC.DeleteDC();
    memBitmap.DeleteObject(); CDialog::OnPaint();
    }在OnMouseMove中改成这样的实现:
    void CPatternDlg::OnMouseMove(UINT nFlags, CPoint point) 
    {
    m_cpNewPoint.x = point.x;
    m_cpNewPoint.y = point.y; SendMessage(WM_PAINT, 0, 0);
    }现在有两个问题:
    1 切换窗口后绘图区域还是变成空白的;
    2 绘图是出现卡的情况,估计是SendMessage引起的,但是不知道该怎么解决希望能指点一下,谢谢了
      

  5.   

    SendMessage(WM_PAINT, 0, 0);
    改成Invalidate();
      

  6.   

    SendMessage 换成 Invalidate 或 PostMessage
    SendMessage 要等到响应完成的, 你鼠标的处理本来就是在消息循环中的,等于卡自己脖子
      

  7.   

    SendMessage 换成 Invalidate 或 PostMessage
      

  8.   

    可不得了了
    换成Invalidate,在窗口上移动鼠标时,呼呼滴刷新,就给风吹动水面似的;
    换成PostMessage和使用SendMessage效果是一样的
      

  9.   

    To hankcs:
    “如果你希望在鼠标拖动的时候实时显示,那么在鼠标处理事件中也要GetDC然后双缓冲绘图”
    你的意思是说
    在OnMouseMove中也要和OnDraw中一样实现吗?
    先绘到内存DC,然后拷贝到屏幕上?
      

  10.   

    你要处理OnErasBkgnd
    在里面返回true
      

  11.   

    哪位有例子
    类似Windows自带的画图工具
    只支持鼠标绘图就可以
    现在感觉越来越乱了
      

  12.   

    你要处理OnErasBkgnd
    我试了,窗口虽然不闪了,但是整个窗口背景成了白的
      

  13.   

    对啊,你鼠标改变了那部分就重画那部分,要是鼠标动一下就全重画不闪花眼才怪
    http://download.csdn.net/source/603538例子很多吧
      

  14.   

    1. 你没处理WM_PAINT, 缺调用了pWnd->Invalidate();结果就是你在OnMouseMove中画完之后,WM_PAINT接着画,把你画的都干掉了2.memDC.BitBlt(Startx,Starty,Startx+wid,Starty+lon, pDC,0,0,SRCCOPY);
    这是干嘛?看不懂
    3.内存DC memDC要载入位图之后才能绘图
    HBITMAP hBmp = CreateCompatibleBitmap(pDC);
    HBITMAP hOldBmp = memDC.SelectObject(hBmp);
      

  15.   

    有道理,这里有个好例子http://download.csdn.net/source/2687885
      

  16.   

    1. "你没处理WM_PAINT",OnPaint不是对WM_PAINT消息的响应函数吗?2. memDC.BitBlt(Startx,Starty,Startx+wid,Starty+lon, pDC,0,0,SRCCOPY);
    是由内存DC拷贝到屏幕上,不知道除了拷贝区域的范围可能不准确外,还有别的错误吗?3. “内存DC memDC要载入位图之后才能绘图”这段代码和你写的一样吧?
    memDC.CreateCompatibleDC(pDC);   
    memBitmap.CreateCompatibleBitmap(pDC,rect.right,rect.bottom);
    pOldBmp = memDC.SelectObject(&memBitmap);
      

  17.   

    To hankcs:
    非常感谢你的热心帮助,但是“有道理,这里有个好例子http://download.csdn.net/source/2687885”这个例子的下载页面里面是空的,什么都没有
      

  18.   

    各位,我现在的问题是:
    1. 我想实现鼠标绘图,是那种伴随鼠标移动而动态出现鼠标移动痕迹的绘图,不是只绘制鼠标按下和弹起两个点之间的先的绘图。为了响应WM_PAINT消息时可以重绘图片,我是不是需要在鼠标移动处理函数中用数组记录下每个点的坐标?
    2. 如果记录的话怎么记录,三维数组?还有没有别的方法?
    3. 以上1, 2的思路是不是有问题?
      

  19.   

    我错了
    每一条线就是一个数组
    记录了这条线经过的点
    可以考虑用CArray
      

  20.   

    保存手动绘制的图片时又碰到一个问题:
    ——————————————————————————————————————
    |          标题栏                                                         |
    ——————————————————————————————————————
    |          A区域(非保存区域)                                            |
    ——————————————————————————————————————
    |                                                                 |
    |          B区域(绘图区域,保存区域)                                    |
    |                                                                 |
    |                                                                 |
    |                                                                 |
    ——————————————————————————————————————我想把B区域保存为BMP文件,但是保存出来之后是A区域和B区域,我怀疑这部分代码有问题,请高人给看一下:
    CDC *dcDrawClient = NULL;
    CDC dcMemDC;
    CBitmap cbBitmap;
    GetDlgItem(IDC_STC_PIC)->GetWindowRect(&rect);
    pCWnd = GetDlgItem(IDC_STC);
    dcDrawClient = pCWnd->GetDC();
    cbBitmap.CreateCompatibleBitmap(dcDrawClient, rect.right, rect.bottom);
    dcMemDC.CreateCompatibleDC(dcDrawClient);
    CBitmap *pcbOldBitmap = (CBitmap *)dcMemDC.SelectObject(&cbBitmap);
    dcMemDC.FillRect(&rect, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
    cpPen.CreatePen(PS_SOLID, m_nLineWidth, RGB (0, 0 , 0));
    pOldPen = dcMemDC.SelectObject(&cpPen);
    for (int i = 0; i < m_Array.GetSize(); i++)
    {
    dcMemDC.MoveTo(((CLines *)m_Array.GetAt(i))->m_ptOrigin);
    dcMemDC.LineTo(((Lines *)m_Array.GetAt(i))->m_ptEnd);
    }
    dcMemDC.SelectObject (pOldPen);
    dcMemDC.SelectObject(pcbOldBitmap);
    ::OpenClipboard(this->m_hWnd);
    ::EmptyClipboard();
    ::SetClipboardData(CF_BITMAP, cbBitmap);
    ::CloseClipboard();