滚动时闪烁 [英] Flickering on scrolling

查看:149
本文介绍了滚动时闪烁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在对话框上有一个CStatic图片控件.我正在使用OnPaint()函数中的StretchDIBits在图片控件中绘制图像.为了进行滚动和缩放,我使用了
中所述的类CZoomCtrl CZoomCtrl:具有缩放和滚动功能的图片控件 [ ^ ]

问题是,每当滚动大图像时,都会出现很多闪烁.

请帮助我摆脱困境.


我刚刚从CZoomCtrl类更改了这两个函数.
这是我的代码:

I have a CStatic picture control on dialog. I am painting an image in picture control using StretchDIBits in OnPaint() function. For Scrolling and zooming purpose I have used class CZoomCtrl stated in
CZoomCtrl: A Picture Control with Zooming and Scrolling[^]

Problem is that whenever I am scrolling big images, lot of flickering occurs.

Please do help me to get out of it.


I just changed these 2 function from CZoomCtrl class.
Here is my code:

void CZoomCtrl::OnPaint()
{
	CPaintDC dc(this);
	//Draw(&dc);


	HDC hDC = dc.GetSafeHdc();
	Preview(hDC);   
}

void CZoomCtrl::Preview(HDC& hDC)
{
    CDC* pDC = CDC::FromHandle(hDC);
  CRect rCanvas, rImg;
  GetClientRect(&rCanvas);               // rCanvas is size of picture control
  pDC->FillSolidRect(&rCanvas,m_canvasColor);
  int imgH = FreeImage_GetHeight(dispImage);      //dispImage is an object of fipImage (class of freeImage)
  int imgW = FreeImage_GetWidth(dispImage);

  rImg = instImg.GetCanvasSize();        // rImg is image size
  PrepDC(pDC, rImg, rImg);

  SetStretchBltMode(hDC, STRETCH_DELETESCANS);
  StretchDIBits(hDC,
        // destination rectangle
        0,0,
        imgW,
        imgH,
        // source rectangle
        0,0,
        imgW,
        imgH,
        FreeImage_GetBits(dispImage),
        FreeImage_GetInfo(dispImage),
        DIB_RGB_COLORS,
        SRCCOPY);

}

推荐答案



很容易看出为什么您会在窗口中看到闪烁.您正在窗口设备上下文上执行两个大型绘图操作.

首先,您似乎正在通过调用FillSolidRect来清除/擦除窗口:
Hi,

It is easy to see why you see flickering in the window. You are performing two large drawing operations on the window device context.

First you appear to be clearing/erasing the window with a call to FillSolidRect:
pDC->FillSolidRect(&rCanvas,m_canvasColor);



然后,稍后将位图位绘制到设备上下文中.



Then later on you draw your bitmap bits into the device context.

StretchDIBits(hDC,
        // destination rectangle
        0,0,
        imgW,
        imgH,
        // source rectangle
        0,0,
        imgW,
        imgH,
        FreeImage_GetBits(dispImage),
        FreeImage_GetInfo(dispImage),
        DIB_RGB_COLORS,
        SRCCOPY);



这两个较大的绘制操作可能会导致闪烁,因为对FillSolidRect的调用被绘制在屏幕上并且在很短的时间内可见.在绘制位图时,用户已经看到了背景色的闪烁.

我建议以下内容:

1.)确保您没有擦除屏幕以响应WM_ERASEBACKGROUND消息.
2.)实现一个存储设备上下文/位图,并用FillSolidRect填充它.在这些内存缓冲区中完成所有绘图.
3.)在OnPaint函数的末尾,将您的内存位图的内容一口气扫到了窗口设备上下文中.
4.)如果在此之后仍然看到闪烁...,请确保层次结构中的所有父窗口都已正确剪切.

本质上,您希望在与窗口关联的设备上下文上执行1次绘制操作...而不是2,3或30.

我还建议您阅读在MFC中进行无闪烁绘制 [ ^ ]由Keith规则 [



These two large drawing operations may cause flicker because the call to FillSolidRect is being painted on the screen and visible for a very brief period. By the time you have drawn your bitmap the user has seen a flash of the background color.

I recommend the following:

1.) Make sure that you are not erasing the screen in response to the WM_ERASEBACKGROUND message.
2.) Implement a memory device context/bitmap and fill that with your FillSolidRect. Do all of your drawing inside these memory buffers.
3.) At the end of your OnPaint function bit blit the contents of your memory bitmap into the window device context in one fell swoop.
4.) If you still see flickering after this... make sure that all of the parent windows in the hierarchy are properly clipping.

Essentially you want 1 drawing operation on the device context associated with the window... not 2,3 or 30.

I would further recommend that you read Flicker Free Drawing In MFC[^] by Keith Rule[^]. Not only does the article have over a half million views... there are thousands of projects using his CMemDC class.

Best Wishes,
-David Delaune

P.S.
I believe that Microsoft added a CMemDC class of their own and gave it the same name with the MFC feature pack. So if you decide to use the CMemDC class and encounter a naming conflict keep this in mind.


大锤方法是将滚动事件包装在对话框的LockWindowUpdates和UnlockWindowUpdates调用中.

否则,可能的原因是对话框或控件正在重新绘制背景.

在您的控件中,尝试拦截WM_ERASEBACKGROUND消息,在这种情况下,什么也不做.默认代码只会将其涂成白色.自己绘制客户区时,不需要它来擦除背景.

如果那不能解决问题,请确保在发生滚动事件时对话框未收到绘制消息.

您可以使用spy ++查看对话框收到的消息,以帮助解决此问题.
A sledgehammer approach would be to wrap your scroll event in calls to LockWindowUpdates and UnlockWindowUpdates for the dialog.

Otherwise, the likely culprit is that the dialog or control is repainting the background.

In your control, try intercepting the WM_ERASEBACKGROUND message and in that event, do nothing. The default code will just paint it white. You don''t need it to erase the background when you''re painting the client area yourself.

If that doesn''t fix it, then make sure that the dialog is not getting a paint message when the scroll event occurs.

You can use spy++ to see what messages your dialog is getting, to help troubleshoot this.


您可以将图像绘制在内存DC上,而不是直接在绘制DC上绘制. />
尝试CreateCompatibleDC和CreateCompetibleBitmap
关于Win32 Memory DC的指南 [ ^ ]
you can paint your image on a memory DC instead of paint it directly on your paint DC.

try CreateCompatibleDC and CreateCompetibleBitmap
Guide to Win32 Memory DC[^]


这篇关于滚动时闪烁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆