Invalidate(); 执行时,是先用背景刷清屏以后,再重新绘画
InvalidateRect(rect), 他执行时, rect区域以背景刷清屏,rect以外的区域不调用背景刷,而是将屏幕上现有的内容(如图片图形等)作为背景,在这个背景上直接画图。
若是,图片和背景反差很大,则使用Invalidate() 会发生闪烁
而使用Invalidate(rect), 则可以将闪烁降低到图片的边缘位置
具体方法如下:
平移时,如果直接翻盖原来的图片,则不会闪烁,但是这时,图片移动后,原图片的边缘位置已经无效,可是由于我们没有清屏,所以它还显示在图片上,这是不应该的。
如果能让图片直接覆盖原有的图片,并且,又让图片失效的边缘部分清屏的话,那我们就可以解决这个问题了。
首先, 我们确定好边缘处需要刷新的区域shuanxinRect
然后,调用InvalidateRect(rect) 即可
注意,移动时,不要使的整个客户区clientRect都清屏,因为那样,会产生闪烁。
我们的原则是:改直接覆盖的,则直接覆盖,改清屏的则清屏
同时,要注意:InvalidateRect(rect) 使用的是对话框的坐标系,而不是绘图控件的坐标系。
所以,若是两坐标系不同的话,先要通过 kongJian->ClientToScreen(&rect); this->ScreenToClient(&rect) 进行转换,转换完毕后,才可以调用InvalidateRect(rect);
下面是我在项目中摘取的一段示例程序:使用四个方向键来控制图片的平移
void CShowImageDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { // TODO: 在此添加消息处理程序代码和/或调用默认值 switch (nChar) { case VK_LEFT: m_isKeyMoving=TRUE; if(!m_lock) //移动图片 用方向键控制移动图片 { GetDlgItem(IDC_MOVE)->SetFocus(); CRect rect; m_RectTracker.GetTrueRect(&rect); m_RectTracker.m_rect.SetRect(rect.TopLeft().x-10,rect.TopLeft().y,rect.BottomRight().x-10,rect.BottomRight().y); m_RectTracker.GetTrueRect(&rect); // 调整以后,取得的新矩形位置 m_pGraphics->DrawImage(m_pImageObj,rect.TopLeft().x,rect.TopLeft().y,rect.Width(),rect.Height()); CRect clientRect; m_image.GetClientRect(&clientRect); CRect shuanxinRect; if (rect.BottomRight().x<clientRect.BottomRight().x) //确定刷新区域 { shuanxinRect.TopLeft().x=rect.BottomRight().x; if(rect.TopLeft().y>0) shuanxinRect.TopLeft().y=rect.TopLeft().y; else shuanxinRect.TopLeft().y=0; shuanxinRect.BottomRight().x=clientRect.BottomRight().x; shuanxinRect.BottomRight().y=clientRect.BottomRight().y; //clientRect与rect shuanxinRect 用的都是m_image客户区坐标, 而InvalidateRect RedrawWindow用的却是对话框客户区坐标 //所以在使用InvalidateRect RedrawWindow 之前 必须将其他坐标系下的坐标进行转换,否则不能按预想的执行 m_image.ClientToScreen(shuanxinRect); this->ScreenToClient(shuanxinRect); RedrawWindow(shuanxinRect); } DrawRectLock(); }else{ GetDlgItem(IDC_LOCK)->SetFocus(); int width=0; int height=0; int x=0; int y=0; CRectTracker_Lock *p=headRectTraker; if(p!=NULL) { //画区域 width=m_step; height=p->rectLock.m_rect.Height(); x=p->rectLock.m_rect.TopLeft().x-m_step; y=p->rectLock.m_rect.TopLeft().y; int image_x=p->radio_distance_x*m_pImageObj->GetWidth()-((double)m_step/m_RectTracker.m_rect.Width())*m_pImageObj->GetWidth(); int image_y=p->radio_distance_y*m_pImageObj->GetHeight(); int image_width=((double)m_step/m_RectTracker.m_rect.Width())*m_pImageObj->GetWidth(); int image_height=p->radio_height*m_pImageObj->GetHeight(); Pen pen(Color(255,255,0,0),2); m_pGraphics->DrawRectangle(&pen,x,y,width,height); CRect rect2; m_RectTracker2.m_rect.SetRect(0,0,image_width,image_height); m_RectTracker2.GetTrueRect(&rect2); RectF rect2Des; rect2Des.X=rect2.TopLeft().x; rect2Des.Y=rect2.TopLeft().y; rect2Des.Width=rect2.Width(); rect2Des.Height=rect2.Height(); m_image2.ClientToScreen(rect2); this->ScreenToClient(rect2); Graphics graphics2(m_image2.GetDC()->GetSafeHdc()); graphics2.DrawImage(m_pImageObj,rect2Des,image_x,image_y,image_width,image_height,UnitPixel); } } break; case VK_RIGHT: m_isKeyMoving=TRUE; if(!m_lock) //移动图片 用方向键控制移动图片 { GetDlgItem(IDC_MOVE)->SetFocus(); CRect rect; m_RectTracker.GetTrueRect(&rect); m_RectTracker.m_rect.SetRect(rect.TopLeft().x+10,rect.TopLeft().y,rect.BottomRight().x+10,rect.BottomRight().y); m_RectTracker.GetTrueRect(&rect); // 调整以后,取得的新矩形位置 m_pGraphics->DrawImage(m_pImageObj,rect.TopLeft().x,rect.TopLeft().y,rect.Width(),rect.Height()); CRect clientRect; m_image.GetClientRect(&clientRect); CRect shuanxinRect; if (rect.TopLeft().x>clientRect.TopLeft().x) { shuanxinRect.TopLeft().x=clientRect.TopLeft().x; shuanxinRect.TopLeft().y=clientRect.TopLeft().y; shuanxinRect.BottomRight().x=rect.TopLeft().x; shuanxinRect.BottomRight().y=clientRect.BottomRight().y; //clientRect与rect shuanxinRect 用的都是m_image客户区坐标, 而InvalidateRect RedrawWindow用的却是对话框客户区坐标 //所以在使用InvalidateRect RedrawWindow 之前 必须将其他坐标系下的坐标进行转换,否则不能按预想的执行 m_image.ClientToScreen(shuanxinRect); this->ScreenToClient(shuanxinRect); RedrawWindow(shuanxinRect); } DrawRectLock(); } break; case VK_DOWN: m_isKeyMoving=TRUE; if(!m_lock) //移动图片 用方向键控制移动图片 { GetDlgItem(IDC_MOVE)->SetFocus(); CRect rect; m_RectTracker.GetTrueRect(&rect); m_RectTracker.m_rect.SetRect(rect.TopLeft().x,rect.TopLeft().y+10,rect.BottomRight().x,rect.BottomRight().y+10); m_RectTracker.GetTrueRect(&rect); // 调整以后,取得的新矩形位置 m_pGraphics->DrawImage(m_pImageObj,rect.TopLeft().x,rect.TopLeft().y,rect.Width(),rect.Height()); CRect clientRect; m_image.GetClientRect(&clientRect); CRect shuanxinRect; if (rect.TopLeft().y>clientRect.TopLeft().y) { shuanxinRect.TopLeft().x=clientRect.TopLeft().x; shuanxinRect.TopLeft().y=clientRect.TopLeft().y; shuanxinRect.BottomRight().x=clientRect.BottomRight().x; shuanxinRect.BottomRight().y=rect.TopLeft().y; //clientRect与rect shuanxinRect 用的都是m_image客户区坐标, 而InvalidateRect RedrawWindow用的却是对话框客户区坐标 //所以在使用InvalidateRect RedrawWindow 之前 必须将其他坐标系下的坐标进行转换,否则不能按预想的执行 m_image.ClientToScreen(shuanxinRect); this->ScreenToClient(shuanxinRect); RedrawWindow(shuanxinRect); } DrawRectLock(); } break; case VK_UP: m_isKeyMoving=TRUE; if(!m_lock) //移动图片 用方向键控制移动图片 { GetDlgItem(IDC_MOVE)->SetFocus(); CRect rect; m_RectTracker.GetTrueRect(&rect); m_RectTracker.m_rect.SetRect(rect.TopLeft().x,rect.TopLeft().y-10,rect.BottomRight().x,rect.BottomRight().y-10); m_RectTracker.GetTrueRect(&rect); // 调整以后,取得的新矩形位置 m_pGraphics->DrawImage(m_pImageObj,rect.TopLeft().x,rect.TopLeft().y,rect.Width(),rect.Height()); CRect clientRect; m_image.GetClientRect(&clientRect); CRect shuanxinRect; if (rect.BottomRight().y<clientRect.BottomRight().y) { shuanxinRect.TopLeft().x=clientRect.TopLeft().x; shuanxinRect.TopLeft().y=rect.BottomRight().y; shuanxinRect.BottomRight().x=clientRect.BottomRight().x; shuanxinRect.BottomRight().y=clientRect.BottomRight().y; //clientRect与rect shuanxinRect 用的都是m_image客户区坐标, 而InvalidateRect RedrawWindow用的却是对话框客户区坐标 //所以在使用InvalidateRect RedrawWindow 之前 必须将其他坐标系下的坐标进行转换,否则不能按预想的执行 m_image.ClientToScreen(shuanxinRect); this->ScreenToClient(shuanxinRect); RedrawWindow(shuanxinRect); } DrawRectLock(); } break; } CDialog::OnKeyDown(nChar, nRepCnt, nFlags); }