双缓冲??????还是闪!!!!!!!!高分!!

时间:2021-07-11 17:32:38
void CFlickerView::OnDraw(CDC* pDC)
{
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);

CBitmap Bitmap;
Bitmap.LoadBitmap(IDB_BITMAP1);
BITMAP bm;
Bitmap.GetObject(sizeof(BITMAP), &bm);

CBitmap *pOldBitmap = MemDC.SelectObject(&Bitmap);
pDC->BitBlt(100, 100, bm.bmWidth, bm.bmHeight, &MemDC, 0, 0, SRCCOPY);

MemDC.SelectObject(pOldBitmap);
MemDC.DeleteDC();
Bitmap.DeleteObject();

//Invalidate();
}


这是用了双缓冲了,可是在改变窗口大小时还是闪的要命!!!!!!(把那个注释的Invalidate();加上观察一下,呵呵.....晕~~~~~~)

到底要怎么彻底避免闪烁呢?
解决了,给你多少分,随你要!!!

9 个解决方案

#1


BOOL CFlickerView::OnEraseBkgnd(CDC* pDC)
{
return FALSE;
}

#2


回复人: hnyyy(前进) ( ) 信誉:111  2003-02-16 14:24:00  得分:0 
 
 
  BOOL CFlickerView::OnEraseBkgnd(CDC* pDC)
{
return FALSE;
}
  
 

这样一来,整个客户区的内容,除了我画的图形外,将会把它后面的图像全粘了上来???

好难看呀???

#3


在OnDraw中画背景

CRect rect;
GetClientRect(rect);
......
memBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
......
MemDC.FillSolidRect(rect, RGB(255, 255, 255));//画背景
......
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &MemDC, 0, 0, SRCCOPY);//全铺满
......

#4


原来是让我把整个客户区全部重画呀!!!

倒~~~~~
不过确实是达到了目的。

#5


发现,在窗口改变大小时,那个ToolBar也闪?

难道当初MS也没处理这个问题???????

#6


OnEraseBkgnd中返回TRUE;
OnDraw中不要加Invalidate,这不是死循环吗!

#7


OnDraw中不要加Invalidate,这不是死循环吗!

这样可以观测效果,免得我自己去拖动更改窗口大小来看闪烁的情况

#8


窗口改变大小时闪的东西多着呢,对于改变大小这种不常发生的事情有一小点闪大概是可以接受的吧?

#9


我觉得应该屏蔽setredraw,然后操作,最后刷新,下面文章参考。

    在图像的编程中,经常会遇到这样一种情况,在有限的区域中显示了一幅大图,这时要浏览图像的各个部分,这就需要用到图像的滚动。关于它的实现,许多书都有提及,但其中的关键点和难点,即拖动中的刷新和闪烁问题,却讲述的不多,这也是我写本文的目的所在,下面我将详细分析实现方法。

    实现效果及实现方法:

    在图像区域中按下鼠标左键,可拖动图像在某一有限区域中任意滚动。

    方法为 :拖动时计算上次与本次的偏移,然后将图像显示的起始点进行变化并刷新图像区域。

    实现部分:

    第一步:响应WM_LBUTTONDOWN 消息,记录按下开始拖动的起始位置。

    void CWingImgDlg::OnLButtonDown(UINT nFlags, CPoint point) 

    {

      // TODO: Add your message handler code here and/or call default

      m_lPicOldLeft = point.x;

      m_lPicOldTop = point.y;

      CDialog::OnLButtonDown(nFlags, point);

    }

    第二步:响应WM_MOUSEMOVE 消息,实现滚动。

    void CWingImgDlg::OnMouseMove(UINT nFlags, CPoint point) 

    {

      // TODO: Add your message handler code here and/or call default

      file://如果鼠标按下 

      if( (nFlags & MK_LBUTTON) == MK_LBUTTON )

      {

        m_lPicNewLeft = point.x;

        m_lPicNewTop = point.y;

        DWORD dwLRShift = m_lPicNewLeft - m_lPicOldLeft;

        DWORD dwTBShift = m_lPicNewTop - m_lPicOldTop;

        file://改变图像显示的起始点

        m_lPicLeft = m_lPicLeft - dwLRShift;

        m_lPicTop = m_lPicTop - dwTBShift;

        file://判断边界的语句,省去。

        m_lPicOldLeft = m_lPicNewLeft;

        m_lPicOldTop = m_lPicNewTop;

        file://进行刷新的语句,见第四步。

      }

      CDialog::OnMouseMove(nFlags, point);

    }

    第三步:在OnPaint中显示,显示的其他部分,如图像的得来等,省去。

    void CWingImgDlg::OnPaint() 

      {

        CPaintDC dc(this); // device context for painting

        file://其他的显示内容,省去。

        if(m_pImgInfo != NULL)

          dc.BitBlt(m_wShowAdjLeft,m_wShowAdjTop,m_lWidth,m_lHeight,&m_AdjDC,

          m_lPicLeft,m_lPicTop,SRCCOPY);

          CDialog::OnPaint();

        }

    第四步:刷新处理。

      最常想到的方法,当然是使用Invalidate(TRUE);//刷新整个无效区

      UpdateWindow();

      这时,会刷新整个程序区域的无效区,闪烁非常严重,改正如下:

        InvalidateRect(&m_rtPic,TRUE); file://仅刷新图像显示区域

        UpdateWindow();

      此时,仅会刷新图像所在区域,闪烁有所缓解,再进一步,可使用

        InvalidateRect(&m_rtPic,TRUE); file://使用快速重画

        ReDrawWindow(&m_rtPic,NULL,RDW_INTERNALPAINT| RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);

进行处理,此时闪烁更进一步减小,考虑到,其他部分可能影响刷新区域,干脆将OnPaint()直接使用在此处,即变为:

    OnPaint(); 

    但如果在OnPaint()中有大量的绘图语句,这种方法仍旧不可行,考虑到不能激发OnPaint()这一因素及控制刷新范围,我采用了如下非标准的方法解决,代码如下:

    CDC *pDC;

    pDC = GetDC();

    if(m_pImgInfo != NULL)

      pDC->BitBlt(m_wShowLeft,m_wShowTop,m_lWidth,m_lHeight,&m_AdjDC,m_lPicLeft,m_lPicTop,SRCCOPY);

      ReleaseDC(pDC);

    这种方法很好地解决了刷新闪烁的问题,图像拖动时很平稳且无闪烁。

#1


BOOL CFlickerView::OnEraseBkgnd(CDC* pDC)
{
return FALSE;
}

#2


回复人: hnyyy(前进) ( ) 信誉:111  2003-02-16 14:24:00  得分:0 
 
 
  BOOL CFlickerView::OnEraseBkgnd(CDC* pDC)
{
return FALSE;
}
  
 

这样一来,整个客户区的内容,除了我画的图形外,将会把它后面的图像全粘了上来???

好难看呀???

#3


在OnDraw中画背景

CRect rect;
GetClientRect(rect);
......
memBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
......
MemDC.FillSolidRect(rect, RGB(255, 255, 255));//画背景
......
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &MemDC, 0, 0, SRCCOPY);//全铺满
......

#4


原来是让我把整个客户区全部重画呀!!!

倒~~~~~
不过确实是达到了目的。

#5


发现,在窗口改变大小时,那个ToolBar也闪?

难道当初MS也没处理这个问题???????

#6


OnEraseBkgnd中返回TRUE;
OnDraw中不要加Invalidate,这不是死循环吗!

#7


OnDraw中不要加Invalidate,这不是死循环吗!

这样可以观测效果,免得我自己去拖动更改窗口大小来看闪烁的情况

#8


窗口改变大小时闪的东西多着呢,对于改变大小这种不常发生的事情有一小点闪大概是可以接受的吧?

#9


我觉得应该屏蔽setredraw,然后操作,最后刷新,下面文章参考。

    在图像的编程中,经常会遇到这样一种情况,在有限的区域中显示了一幅大图,这时要浏览图像的各个部分,这就需要用到图像的滚动。关于它的实现,许多书都有提及,但其中的关键点和难点,即拖动中的刷新和闪烁问题,却讲述的不多,这也是我写本文的目的所在,下面我将详细分析实现方法。

    实现效果及实现方法:

    在图像区域中按下鼠标左键,可拖动图像在某一有限区域中任意滚动。

    方法为 :拖动时计算上次与本次的偏移,然后将图像显示的起始点进行变化并刷新图像区域。

    实现部分:

    第一步:响应WM_LBUTTONDOWN 消息,记录按下开始拖动的起始位置。

    void CWingImgDlg::OnLButtonDown(UINT nFlags, CPoint point) 

    {

      // TODO: Add your message handler code here and/or call default

      m_lPicOldLeft = point.x;

      m_lPicOldTop = point.y;

      CDialog::OnLButtonDown(nFlags, point);

    }

    第二步:响应WM_MOUSEMOVE 消息,实现滚动。

    void CWingImgDlg::OnMouseMove(UINT nFlags, CPoint point) 

    {

      // TODO: Add your message handler code here and/or call default

      file://如果鼠标按下 

      if( (nFlags & MK_LBUTTON) == MK_LBUTTON )

      {

        m_lPicNewLeft = point.x;

        m_lPicNewTop = point.y;

        DWORD dwLRShift = m_lPicNewLeft - m_lPicOldLeft;

        DWORD dwTBShift = m_lPicNewTop - m_lPicOldTop;

        file://改变图像显示的起始点

        m_lPicLeft = m_lPicLeft - dwLRShift;

        m_lPicTop = m_lPicTop - dwTBShift;

        file://判断边界的语句,省去。

        m_lPicOldLeft = m_lPicNewLeft;

        m_lPicOldTop = m_lPicNewTop;

        file://进行刷新的语句,见第四步。

      }

      CDialog::OnMouseMove(nFlags, point);

    }

    第三步:在OnPaint中显示,显示的其他部分,如图像的得来等,省去。

    void CWingImgDlg::OnPaint() 

      {

        CPaintDC dc(this); // device context for painting

        file://其他的显示内容,省去。

        if(m_pImgInfo != NULL)

          dc.BitBlt(m_wShowAdjLeft,m_wShowAdjTop,m_lWidth,m_lHeight,&m_AdjDC,

          m_lPicLeft,m_lPicTop,SRCCOPY);

          CDialog::OnPaint();

        }

    第四步:刷新处理。

      最常想到的方法,当然是使用Invalidate(TRUE);//刷新整个无效区

      UpdateWindow();

      这时,会刷新整个程序区域的无效区,闪烁非常严重,改正如下:

        InvalidateRect(&m_rtPic,TRUE); file://仅刷新图像显示区域

        UpdateWindow();

      此时,仅会刷新图像所在区域,闪烁有所缓解,再进一步,可使用

        InvalidateRect(&m_rtPic,TRUE); file://使用快速重画

        ReDrawWindow(&m_rtPic,NULL,RDW_INTERNALPAINT| RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);

进行处理,此时闪烁更进一步减小,考虑到,其他部分可能影响刷新区域,干脆将OnPaint()直接使用在此处,即变为:

    OnPaint(); 

    但如果在OnPaint()中有大量的绘图语句,这种方法仍旧不可行,考虑到不能激发OnPaint()这一因素及控制刷新范围,我采用了如下非标准的方法解决,代码如下:

    CDC *pDC;

    pDC = GetDC();

    if(m_pImgInfo != NULL)

      pDC->BitBlt(m_wShowLeft,m_wShowTop,m_lWidth,m_lHeight,&m_AdjDC,m_lPicLeft,m_lPicTop,SRCCOPY);

      ReleaseDC(pDC);

    这种方法很好地解决了刷新闪烁的问题,图像拖动时很平稳且无闪烁。