• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 821
  • Last Modified:

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.
0
brosenb0
Asked:
brosenb0
1 Solution
 
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
 
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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
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
 
psdavisCommented:
// 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
 
brosenb0Author Commented:
Thanks Phillip that was just what I was after.

Bruce.
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now