关于窗口重绘

来源:互联网 发布:linux新建目录命令 编辑:程序博客网 时间:2024/04/27 22:03

还是<<VC技术内幕>>里面一段代码 ,可以用鼠标拖动一个圆 :

void CEx05cView::OnDraw(CDC* pDC)
{
    CBrush brushHatch(HS_DIAGCROSS, RGB(255, 0, 0));
    CPoint point(0, 0);                  // logical (0, 0)
   
    pDC->LPtoDP(&point);                 // In device coordinates,
    pDC->SetBrushOrg(point);             //  align the brush with
                                         //  the window origin
    pDC->SelectObject(&brushHatch);
    pDC->Ellipse(CRect(m_pointTopLeft, m_sizeEllipse));
    pDC->SelectStockObject(BLACK_BRUSH); // Deselect brushHatch
    pDC->Rectangle(CRect(100, -100, 200, -200)); // Test invalid rect
}

void CEx05cView::OnMouseMove(UINT nFlags, CPoint point)
{
    if (m_bCaptured) {
        CClientDC dc(this);
        OnPrepareDC(&dc);
        CRect rectOld(m_pointTopLeft, m_sizeEllipse);
        dc.LPtoDP(rectOld);
        InvalidateRect(rectOld, TRUE);

        m_pointTopLeft = point - m_sizeOffset;
        dc.DPtoLP(&m_pointTopLeft);
        CRect rectNew(m_pointTopLeft, m_sizeEllipse);
        dc.LPtoDP(rectNew);
        InvalidateRect(rectNew, TRUE);
    }
}

我之所以不明白,是对重绘很模糊.关键是OnMouseMove里面的两次调用invalidate函数让我很是迷惑,于是,老规矩,上csdn发帖子,高人指点如下:

两次InvalidateRect实际只能产生一个WM_PAINT消息(就是OnDraw只能被调用一次,因为这个消息会被合并),但是被擦除的区域是包含了rectOld和rectNew两个部分的。
InvalidateRect的第二个参数TRUE是说要擦除背景,OnDraw被调用之前rectOld和rectNew两个矩形都被擦成背景色了(就是说原来的圆被擦掉了),OnDraw里只画了新的圆。最后你看到的就是一个新的圆。

InvalidateRect(hWnd,&rect,TRUE);向hWnd窗体发出WM_PAINT的消息,强制客户区域重绘制,
rect是你指定要刷新的区域,此区域外的客户区域不被重绘,这样防止客户区域的一个局部的改动,而导致整个客户区域重绘而导致闪烁,如果最后的参数为TRUE,则还向窗体发送WM_ERASEBKGND消息,使背景重绘,当然在客户区域重绘之前。
UpdateWindow只向窗体发送WM_PAINT消息,在发送之前判断GetUpdateRect(hWnd,NULL,TRUE)看有无可绘制的客户区域,如果没有,则不发送WM_PAINT
InvalidateRect只是放一个WM_PAINT消息在队列里,不做别的,所以只有当当前函数返回后,进入消息循环,取出WM_PAINT,才执行PAINT,所以不管InvalidateRect放哪里,都是最后执行的。

自己的理解: 首先必须明白invalidate这个函数到底干什么事情了,根据以上前辈的指点以及我在msdn上的查询,可以说invalidate干了两件事:

(1)把某个区域加入到update region里面,当windows检测到update region不为空时,就会产生wm_paint消息,所以上面前辈说的 "invalidate只是放一个WM_PAINT消息在队列里" 应该也是这个意思.有一点值得注意,上面提到的, "所以不管InvalidateRect放哪里,都是最后执行的。" 在函数里面调用invalidate,在函数执行后才执行paint的.所以,上面代码有两个invalidate,是把原来的矩形和新的矩形都加入到update region里,然后调用onpaint函数,对并且仅仅对update region进行重绘.

(2) 如果invalidate的第二个参数为TRUE,那么会对背景进行擦除,注意这里的擦除,应该是只是对update region区域背景的擦除.所以上面代码,首先是把两个矩形都加进update region里面,同时对背景擦除,然后调用onpaint函数对新圆进行重绘,于是就实现了用鼠标拖动圆的效果.

所以暂时这样理解,在某个函数里面调用invalidate是把某个区域加入更新区域,同时确定是否对这些更新区域的背景擦除,然后函数返回后会调用onpaint或者ondraw函数对特定区域重绘.

原创粉丝点击