InvalidateRect(rect) 防止图片移动时发生闪烁

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);
}



版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-05 06:43:03

InvalidateRect(rect) 防止图片移动时发生闪烁的相关文章

C# 使用Graphics绘制图片时发生闪烁的问题

在做某功能时,需要实现用鼠标滚轮放大缩小图片,直接在MouseWheel中绘制图片时发生闪烁 百度后顺利解决 几个步骤 1.设置Form的DoubleBuffered属性为True 2.在MouseWheel中调用 this.Invalidate()方法(会触发OnPaint事件) 3.重写OnPaint,在OnPaint中绘制需要绘制的图像 代码如下: public partial class Form1 : Form { int width, height; string path = "C

图片缩放时java.lang.IllegalArgumentException: pointerIndex out of range解决方案

版权声明:本文为博主原创文章,未经博主允许不得转载. 06-03 20:45:24.143: E/AndroidRuntime(1230): FATAL EXCEPTION: main06-03 20:45:24.143: E/AndroidRuntime(1230): java.lang.IllegalArgumentException: pointerIndex out of range06-03 20:45:24.143: E/AndroidRuntime(1230): at androi

Android ListView滑动过程中图片显示重复错乱闪烁问题解决

转自:http://www.oschina.net/question/221817_121051 主要分析Android ListView滚动过程中图片显示重复.错乱.闪烁的原因及解决方法,顺带提及ListView的缓存机制.1.原因分析ListView item缓存机制:为了使得性能更优,ListView会缓存行item(某行对应的View).ListView通过adapter的getView函数获得每行的item.滑动过程中, a. 如果某行item已经滑出屏幕,若该item不在缓存内,则p

System.ServiceModel.CommunicationException: 接收HTTP 响应时发生错误

具体错误信息如下: System.ServiceModel.CommunicationException: 接收对 http://110.110.110.110/TestService/TestService.svc 的 HTTP 响应时发生错误.这可能是由于服务终结点绑定未使用 HTTP 协议造成的.这还可能是由于服务器中止了 HTTP 请求上下文(可能由于服务关闭)所致.有关详细信息,请参见服务器日志. ---> System.Net.WebException: 基础连接已经关闭: 接收时发

图片缩放时java.lang.IllegalArgumentException: pointerIndex out of range

06-03 20:45:24.143: E/AndroidRuntime(1230): FATAL EXCEPTION: main 06-03 20:45:24.143: E/AndroidRuntime(1230): java.lang.IllegalArgumentException: pointerIndex out of range 06-03 20:45:24.143: E/AndroidRuntime(1230): at android.view.MotionEvent.native

ListView用法及加载数据时的闪烁问题和加载数据过慢问题

ListView介绍及添加数据时的闪烁问题 1.     ListView类 1.1 ListView常用的基本属性: (1)FullRowSelect:设置是否行选择模式.(默认为false) 提示:只有在Details视图该属性才有意义. (2) GridLines:设置行和列之间是否显示网格线.(默认为false)提示:只有在Details视图该属性才有意义. (3)AllowColumnReorder:设置是否可拖动列标头来对改变列的顺序.(默认为false)提示:只有在Details视

Android ListView滑动过程中图片显示重复错位闪烁问题解决[转载]

转自:here 主要分析Android ListView滚动过程中图片显示重复.错乱.闪烁的原因及解决方法,顺带提及ListView的缓存机制.1.原因分析ListView item缓存机制:为了使得性能更优,ListView会缓存行item(某行对应的View).ListView通过adapter的getView函数获得每行的item.滑动过程中, a. 如果某行item已经滑出屏幕,若该item不在缓存内,则put进缓存,否则更新缓存:b. 获取滑入屏幕的行item之前会先判断缓存中是否有可

Android在ListView显示图片(重复错乱闪烁问题)

1.原因分析 ListView item缓存机制: 为了使得性能更优,ListView会缓存行item(某行对应的View). ListView通过adapter的getView函数获得每行的item. 滑动过程中 a. 如果某行item已经滑出屏幕,若该item不在缓存内,则put进缓存,否则更新缓存: b. 获取滑入屏幕的行item之前会先判断缓存中是否有可用的item,如果有,做为convertView参数传递给adapter的getView. 这样,如下的getView写法就可以充分利用

Win7 自带FTP将文件复制到FTP服务器时发生错误。

错误截图: 错误信息: 将文件复制到FTP服务器时发生错误.请检查是否有权限将文件放到该服务器上. 详细信息: 200 Type set to I. 200 PORT commad successful. 451 No mapping for the Unicode character exits in target multi-bye code page. 解决方案: 控制面板-->管理工具-->打开Internet信息服务(IIS)管理器.右键选中自己建立好的FTP站点,选择"管