Solved

Eliminating Flicker in a Property Sheet

Posted on 1998-08-15
12
785 Views
Last Modified: 2013-11-20
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
Comment
Question by:brosenb0
12 Comments
 
LVL 2

Expert Comment

by:warmcat
ID: 1320859
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
 
LVL 8

Expert Comment

by:trestan
ID: 1320860
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
 
LVL 3

Author Comment

by:brosenb0
ID: 1320861
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
 
LVL 8

Expert Comment

by:Answers2000
ID: 1320862
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
 
LVL 3

Author Comment

by:brosenb0
ID: 1320863
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
 
LVL 3

Author Comment

by:brosenb0
ID: 1320864
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
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 7

Expert Comment

by:psdavis
ID: 1320865
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
 
LVL 3

Author Comment

by:brosenb0
ID: 1320866
Sounds good Phil.  Whack it through as an answer and we'll see how we go.
0
 
LVL 23

Expert Comment

by:chensu
ID: 1320867
Apply the WS_CLIPCHILDREN style to the property page (the parent window of the static control).
0
 
LVL 3

Author Comment

by:brosenb0
ID: 1320868
This just stopped the OnPaint() function from being called and the bitmap was not painted at all.
0
 
LVL 7

Accepted Solution

by:
psdavis earned 200 total points
ID: 1320869
// 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
 
LVL 3

Author Comment

by:brosenb0
ID: 1320870
Thanks Phillip that was just what I was after.

Bruce.
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Handling string inputs in C/Linux 23 167
Hibernate methods 2 58
zeroMAx challenge 20 76
Can not remove SSL certificate on iPhone 6 - iOS10.2 12 84
Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now