Eliminating Flicker in a Property Sheet

I've got a CPropertySheet derived class running in wizard mode which contains several property pages.  Each property page displays the same bitmap within a static control in the same location, similar to the familiar InstallShield wizard. When I change between pages, the control's frame and client area is erased (by MFC I assume) and the CPropertyPage derived class for the selected property page's OnPaint() function is called to fill in the bitmap.  This works fine, except the erasing causes noticable flicker.  How can I eliminate this ?

Thanks.
LVL 3
brosenb0Asked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
psdavisConnect With a Mentor Commented:
// Here's the Offset button function that allows you to move everything including the bar and the buttons.

BOOL CMyPropertySheet::OffsetButtons( CPropertySheet* pSheet, CSize& sizOffset )
{
   CTabCtrl* pTabControl = pSheet->GetTabControl( );
   
   for( CWnd* pChild = pSheet->GetWindow( GW_CHILD ); pChild; pChild = pChild->GetNextWindow( GW_HWNDNEXT ))
   {
      if( pChild == pTabControl || pChild == this )
         continue;
     
      CRect rectWindow;
      pChild->GetWindowRect( &rectWindow );
      pSheet->ScreenToClient( &rectWindow );
      rectWindow.OffsetRect( sizOffset );
      pChild->MoveWindow( &rectWindow, TRUE );
   }
   
   return TRUE;
}

CMyPropertyPage::OnSetActive( )
{
.
short sWidth  = 550;
short sHeight = 120;
 
OffsetButtons( pScanWizard, CSize( sWidth, sHeight ));
   
CRect rectWindow;
GetWindowRect( &rectWindow );
pScanWizard->ScreenToClient( &rectWindow );
rectWindow += CRect( 0, 0, sWidth, sHeight );
MoveWindow( &rectWindow, TRUE );
   
pScanWizard->GetWindowRect( &rectWindow );
rectWindow.InflateRect( CSize( sWidth / 2, sHeight / 2 ));
pScanWizard->SetWindowPos( NULL, rectWindow.left, rectWindow.top, rectWindow.Width( ), rectWindow.Height( ), SWP_NOZORDER );

.
}

// and to move it back

CMyPropertySheet::OnKillActive( )
{
.
short sWidth  = 550;
short sHeight =  50;
   
CPropertySheet* pSheet = (CPropertySheet*) GetParent( );
OffsetButtons( pSheet, CSize( -sWidth, -sHeight ));
   
CRect rectWindow;
pSheet->GetWindowRect( &rectWindow );
rectWindow.DeflateRect( CSize( sWidth / 2, sHeight / 2 ));
pSheet->SetWindowPos( NULL, rectWindow.left, rectWindow.top, rectWindow.Width( ), rectWindow.Height( ), SWP_NOZORDER );
.
}

// Hope this helps you!

// Phillip
0
 
warmcatCommented:
You could place the entire CPropertySheet derivation as a child on a dialog.  The CpropertySheet is placed, say, to the right of a bitmap which is a child of the dialog.  Just to be clear, this would remove the bitmap from the property pages and make it a sibling of the property sheet on an underlying substrate dialog.
0
 
trestanCommented:
To avoid flickering, you should use a memory DC. You output the bitmap to the memory DC instead of directly to the screen. Then transfer this bitmap Memory DC to screen which is much faster. So that flickering can be avoided. Use CreateCompatibleDC to create the memory DC, use LoadBitmap or SelectObject to put the bitmap in the DC, and at last use Bitblt to put the bitmap to screen. Good luck.
0
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
brosenb0Author Commented:
Sorry Trestan,
I'm already using a memory DC for painting the bitmap.  The problem seems to be caused by the static control erasing its background when the pages are changed.

Warmcat,
How do I move the property sheet to where ever I want in the dialog's client area? A property sheet is not a control as such and can't be manipulated in the resource editor.  In wizard mode the property sheet draws a sunken line between the pages and its buttons.  How do I tie this in with the parent dialog ?  Got any examples ?
0
 
Answers2000Commented:
The problem is caused because each property sheet is destroyed/hidden and a new one created when you move to the next stage in the wizard.

Each time you move to the next stage in the wizard the you get a new static control (if you do GetDlgItem(ID_WHATEVER)->m_hWnd() on the static you will probably be able to see the hWnd change).

My suggestion to get around this:
Don't use a static control.  Instead override the WM_PAINT message for each property page that that should have the graphics placed placed on it.  Each WM_PAINT message will have to be essentially overridden the same way.  This is tricky but is do-able.  
Take at look at http://www.codeguru.com/propertysheet/index.shtml and in particular an article called "Placing A Bitmap In The PropertySheet Button area".  This code over-rides WM_PAINT for a property sheet.  You should be able to use the same idea for your propertypages.

0
 
brosenb0Author Commented:
Answers2000,

That method may work, however, I will have to include the control's border in the bitmap & calculate the dest. RECT manually. Even if the control was removed, when the freshly selected property page erased its background upon a page change, wouldn't flicker still occur ?  Which is painted last - the sheet or the page ?  If the page is painted last, it would erase the painting done by the sheet.  Is there a way to subclass the static control to stop it erasing its background ?
0
 
brosenb0Author Commented:
Sorry Answers200,
The property sheet still erases each page as they are changed.  With regard to Warmcat's suggestion, placing the sheet inside a dialog is ok for a tabbed property sheet, but no good in wizard mode.

What I might be able to do is remove the static control from each page and create a CStatic control on the sheet itself at runtime.  To do this I would have to leave the pages (at least one) the same size so that the sheet was large enough to accomodate the control.  Next I would have to resize each page before they were drawn so that they don't overwrite the CStatic control.  I found an article at www.codeguru.com that discussed placing a control directly on a property sheet at runtime, however, the method used was to extend the sheet, rather than shrink the pages.  This method worked in tabbed mode, however, with wizard mode this results in the divider bar between the buttons and the pages not being extended correctly and the sheet looks funny.  Does anyone know how to do this ?

Thanks.
0
 
psdavisCommented:
Absolutely, when resizing the pages in wizard mode, use the GetWindow( GW_CHILD ) and cycle through using the GW_HWNDNEXT parameter to move each and every window including the divider bar.  I have full source code to this at work and I'll send it over at 8:20 CST for you!

It is with a Wizard and it grows on page 2 and shrinks on page 3.  It should be exactly what you want.

Phillip
0
 
brosenb0Author Commented:
Sounds good Phil.  Whack it through as an answer and we'll see how we go.
0
 
chensuCommented:
Apply the WS_CLIPCHILDREN style to the property page (the parent window of the static control).
0
 
brosenb0Author Commented:
This just stopped the OnPaint() function from being called and the bitmap was not painted at all.
0
 
brosenb0Author Commented:
Thanks Phillip that was just what I was after.

Bruce.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.