举个需求的例子,在界面上有个十字光标,用键盘上下左右控制其移动。我的方法是响应键盘消息,每次重绘界面和十字光标,但是会造成闪烁,求大家指点该如何实现呢?谢谢

解决方案 »

  1.   

    1、显示的图形为什么会闪烁?
    我们的绘图过程大多放在OnDraw或者OnPaint函数中,OnDraw在进行屏幕
    显示时是由OnPaint进行调用的。当窗口由于任何原因需要重绘时,总是先用
    背景色将显示区清除,然后才调用OnPaint,而背景色往往与绘图内容反差很大,
    这样在短时间内背景色与显示图形的交替出现,使得显示窗口看起来在闪。如果
    将背景刷设置成NULL,这样无论怎样重绘图形都不会闪了。当然,这样做会使
    得窗口的显示乱成一团,因为重绘时没有背景色对原来绘制的图形进行清除,而
    又叠加上了新的图形。
    有的人会说,闪烁是因为绘图的速度太慢或者显示的图形太复杂造成的,其实这
    样说并不对,绘图的显示速度对闪烁的影响不是根本性的。
    例如在OnDraw(CDC *pDC)中这样写: pDC->MoveTo(0,0);
    pDC->LineTo(100,100);
    这个绘图过程应该是非常简单、非常快了吧,但是拉动窗口变化时还是会看见闪
    烁。其实从道理上讲,画图的过程越复杂越慢闪烁应该越少,因为绘图用的时间
    与用背景清除屏幕所花的时间的比例越大人对闪烁的感觉会越不明显。
    比如:清楚屏幕时间为1s绘图时间也是为1s,这样在10s内的连续重画中就要
    闪烁5次;如果清楚屏幕时间为1s不变,而绘图时间为9s,这样10s内的连续
    重画只会闪烁一次。这个也可以试验,在OnDraw(CDC *pDC)中这样写: for(int i=0;i<100000;i++) { pDC->MoveTo(0,i); pDC->LineTo(1000,i);
     }
    说到这里可能又有人要说了,为什么一个简单图形看起来没有复杂图形那么闪呢?
    这是因为复杂图形占的面积大,重画时造成的反差比较大,所以感觉上要闪得厉
    害一些,但是闪烁频率要低。
    那为什么动画的重画频率高,而看起来却不闪?这里,我就要再次强调了,闪烁
    是什么?闪烁就是反差,反差越大,闪烁越厉害。因为动画的连续两个帧之间的
    差异很小所以看起来不闪。如果不信,可以在动画的每一帧中间加一张纯白的帧,
    不闪才怪呢。
    2、如何避免闪烁
    在知道图形显示闪烁的原因之后,对症下药就好办了。首先当然是去掉MFC提
    供的背景绘制过程了。实现的方法很多,* 可以在窗口形成时给窗口的注册类的背景刷付NULL* 也可以在形成以后修改背景static CBrush brush(RGB(255,0,0));SetClassLong(this->m_hWnd,GCL_HBRBACKGROUND,(LONG)(HBRUSH)brush);* 要简单也可以重载OnEraseBkgnd(CDC* pDC)直接返回TRUE.
    这样背景没有了,结果图形显示的确不闪了,但是显示也象前面所说的一样,变
    得一团乱。怎么办?这就要用到双缓存的方法了。双缓冲就是除了在屏幕上有图
    形进行显示以外,在内存中也有图形在绘制。我们可以把要显示的图形先在内存
    中绘制好,然后再一次性的将内存中的图形按照一个点一个点地覆盖到屏幕上去
    (这个过程非常快,因为是非常规整的内存拷贝)。这样在内存中绘图时,随便
    用什么反差大的背景色进行清除都不会闪,因为看不见。当贴到屏幕上时,因为
    内存中最终的图形与屏幕显示图形差别很小(如果没有运动,当然就没有差别),
    这样看起来就不会闪。
    3、如何实现双缓冲
    首先给出实现的程序,然后再解释,同样是在OnDraw(CDC *pDC)中:CDC MemDC; //首先定义一个显示设备对象CBitmap MemBitmap;//定义一个位图对象//随后建立与屏幕显示兼容的内存显示设备
    MemDC.CreateCompatibleDC(NULL);//这时还不能绘图,因为没有地方画 ^_^//下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的
    大小MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight);//将位图选入到内存显示设备中//只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);//先用背景色将位图清除干净,这里我用的是白色作为背景//你也可以用自己应该用的颜色MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255));//绘图MemDC.MoveTo(……);MemDC.LineTo(……); //将内存中的图拷贝到屏幕上进行显示pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY);//绘图完成后的清理MemBitmap.DeleteObject();MemDC.DeleteDC();
    上面的注释应该很详尽了,废话就不多说了。
      

  2.   

    “每次重绘界面和十字光标”限制 重绘区, 比十字光标 略大。
    即 InvalidateRect(十字光标+10)