Click here to Skip to main content
15,040,743 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
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:

C++
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);

}
Posted
Updated 14-Mar-12 8:11am
v4
Comments
Nelek 13-Mar-12 14:20pm
   
Have you programmed it as in the article? How many and what messages are you triggering from where?

I have sometimes had flickering problems as well and it was because I programmed the Clear- and UpdateWindow in OnMouseMove.
DrBones69 13-Mar-12 22:50pm
   
Sometimes calling Invalidate() will solve some flickering issues.

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:
C++
pDC->FillSolidRect(&rCanvas,m_canvasColor);


Then later on you draw your bitmap bits into the device context.
C++
StretchDIBits(hDC,
        // destination rectangle
        0,0,
        imgW,
        imgH,
        // source rectangle
        0,0,
        imgW,
        imgH,
        FreeImage_GetBits(dispImage),
        FreeImage_GetInfo(dispImage),
        DIB_RGB_COLORS,
        SRCCOPY);


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.
   
Comments
Ravikant 15-Mar-12 13:25pm
   
With your suggestions I have added these lines in code after PrepDC():

CBitmap m_OffscreenBitmap, *m_pOldBitmap;
CDC memDC ;
memDC.CreateCompatibleDC(pDC);

HBITMAP bitmap = CreateDIBitmap(hDC, FreeImage_GetInfoHeader(dispImage), CBM_INIT, FreeImage_GetBits(dispImage), FreeImage_GetInfo(dispImage), DIB_RGB_COLORS);

m_OffscreenBitmap.Attach(bitmap);

m_pOldBitmap = memDC.SelectObject(&m_OffscreenBitmap);

memDC.FillSolidRect(&rCanvas,m_canvasColor);
SetStretchBltMode(memDC.GetSafeHdc(), STRETCH_DELETESCANS);
StretchDIBits(memDC.GetSafeHdc(),
// destination rectangle
0,0,
imgW,
imgH,
// source rectangle
0,0,
imgW,
imgH,
FreeImage_GetBits(dispImage),
FreeImage_GetInfo(dispImage),
DIB_RGB_COLORS,
SRCCOPY);
pDC->BitBlt(0, 0, imgW, imgH, &memDC, 0, 0, SRCCOPY);

memDC.SelectObject(m_pOldBitmap);
memDC.DeleteDC();

I am returning false in OnEraseBackground(). I have also commented the line
pDC->FillSolidRect(&rCanvas,m_canvasColor);
With this, flickering is stopped but 2 new problems arised:
1. When image is zoomed out image get distorted...ie lines of red, blue color comes.
2. Scrolling is still not smooth. It looks like some part of image is overlapped over other.

Please help me out.
Randor 15-Mar-12 21:48pm
   
Hi,

Sorry for the late reply. I was out of the office today. Is there any reason for using the STRETCH_DELETESCANS mode? Could you try using HALFTONE? The HALFTONE mode will give a higher quality stretch blit.
Ravikant 16-Mar-12 3:06am
   
Using HALFTONE doesn't solve the problem. Both problems still persist.
One problem is also seen after doing some unit testing. Whenever we zoom in and then zoom out, zoomed in image still there in picture control ie picture control is not refreshed.
After doing some unit testing I think erasing background is necessary as after zoom in when u do zoom out u need to refresh the picture control. If I am wrong pls suggest a better idea.
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.
   
Comments
Ravikant 16-Mar-12 10:25am
   
You mean to say that while scrolling paint message shouldn't be called. Actually in CZoomCtrl class:
void CZoomCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
m_scrollHelper.OnVScroll(nSBCode, nPos, pScrollBar);
Invalidate();
}
Invalidate here calls paint. should i stop that?
JackDingler 16-Mar-12 12:38pm
   
Solution 2 is something you should look at first.
Ravikant 16-Mar-12 12:55pm
   
Thanks JackDingler....your suggestion really worked. Actually in CZoomCtrl on every scrolling invalidate is getting called which actually created fluctuation in code. I removed it and flickering is removed. I don't think I should adopt approach of solution 2 (although i had tried it earlier) when your solution is working fine...

Sorry I didn't read your suggestion seriously before.
Thanks for your support.
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[^]
   
The best way is to override override OnEraseBackground

XML
The best way to "override OnEraseBackground" would be to let ClassWizard add Windows message handler WM_ERASEBKGND into your class.
After doing this you'd have to get
a) in your header:
Code:
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
b) in your cpp:
Code:
BEGIN_MESSAGE_MAP(<your_class> ,<Base_class>)
    //{{AFX_MSG_MAP(<your_class>)
    ON_WM_ERASEBKGND()
    .............
    //}}AFX_MSG_MAP
............
BOOL <your_class>::OnEraseBkgnd(CDC* pDC)
{
    return <Base_class>::OnEraseBkgnd(pDC);
}
   
you should use double buffering

void CZoomCtrl::OnPaint()
{
	CPaintDC dc(this);
	//Draw(&dc);
        CDC dcMem;
        CRect rCanvas;
        GetClientRect(&rCanvas);
        int nWidth = rCanvas.Width(),nHeight = rCanvas.Height();
        dcMem.CreateCompatibleDC(&dc); 
        CBitmap bmpMem;
        bmpMem.CreateCompatibleBitmap(&dc,nWidht,nHeight);
        dcMem.SelectObject(&bmpMem);
	HDC hDC = dcMem.GetSafeHdc(); // here i passed Memory DC handle.
	Preview(hDC);
        dc.BitBlt( 0, 0, nWidth , nHeight , &dcMem, 0, 0, SRCCOPY)//  
}

I hope this works.

--onlybj
   
v3
Comments
Ravikant 16-Mar-12 9:47am
   
With this also it is not working...I am getting these problems
1. When image is zoomed out image get distorted...ie lines of red, blue color comes.
2. Not able to scroll image. On scrolling, same portion of image is shown again and again.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900