读书人

还是窗口重绘的有关问题

发布时间: 2012-03-17 19:06:28 作者: rapoo

还是窗口重绘的问题
下面的代码(一部分),也是 < <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函数呢
第一次调用是使老矩形无效,第二次是使新矩形无效,但是两次应该都是引起ondraw重绘窗口的啊,那怎么实现擦除原来的圆的效果的?

[解决办法]
两次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放哪里,都是最后执行的。



所以说InvalidateRect(rectOld, TRUE);之前,你又新画了一个圆,所以原来老矩形的位置将会根据你新画圆的位置重画整个窗口,除非你的新圆还在原地,不然的话老矩形的位置上的圆将会被擦除.

读书人网 >VC/MFC

热点推荐