none
ShowScrollBar fails to remove scrollbars with animation on Vista/Windows 7

    Question

  • I'm trying to remove both scrollbars in my custom control using the following code:
    Code:
    ShowScrollBar(hWnd, SB_BOTH, FALSE);
    I should say that it works probably 80% of the time. And sometimes I get an artifact of a scrollbar (that I cannot click) left out on the screen. I tried adding the following right after that call, but it didn't seem to help either:
    Code:

    InvalidateRect(hWnd, NULL, TRUE);

    RedrawWindow(hWnd, NULL, NULL, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE);

    UpdateWindow(hWnd);

    I also made a sample project to demonstrate it. You can download it here:
    http://www.codeguru.com/forum/attachment.php?attachmentid=28361&d=1304800109

    Can you try it on your end and see if you get the same result?

    For this to work you need the following:

    1. Windows Vista, or Windows 7 (surprisingly this will work OK on XP)

    2. Default visual styles enabled (maybe "glass effect" too) for the scrollbar to be animated. See my screenshot for how it looks on my end:
    http://www.codeguru.com/forum/attachment.php?attachmentid=28360&stc=1&d=1304800096

    Run the sample project. It should animate what happens....

    Saturday, May 07, 2011 8:38 PM

Answers

  • Try another workaround: execute this line after hiding the scrollbar:

     

    #pragma comment(lib"UxTheme.lib")
    if(IsThemeActive()) ::SetWindowTheme(*thisNULL_T("Scrollbar"));

    • Marked as answer by ahmd0 Sunday, May 08, 2011 6:23 PM
    Sunday, May 08, 2011 9:31 AM

All replies

  • I am seeing the same thing.  This is indeed a bug in the common controls.  What is happening is the scrollbar is fading the away from its hot state but not correctly accounting for the fact that the scrollbar was hidden.  The reason invalidating doesn't work is because the animation continues after the paint and simply draws it again.  If you add a longer delay after moving the mouse away before hiding the scrollbar, this no longer happens because the animation has already completed by that time.  I'm going to continue to investigate a workaround.

    Edit: You can use scroll bars controls instead of the standard scrollbar.  The control won't animate when you destroy it.

    Sunday, May 08, 2011 3:19 AM
  • Thank you. I appreciate you taking time to look into it.

    Yes, I thought of utilizing scrollbar controls but that introduces quite a costly workaround since their use intruduces a whole new ball game of managing them in my code.

    The current workaround that seems to work is to redraw the entire window approx. 2 seconds after the scrollbars were hidden.

    PS. I'm also not sure if anyone at Microsoft is aware of this bug. It was clearly present since Vista release (and still is present in Windows 7)

    Sunday, May 08, 2011 7:32 AM
  • Try another workaround: execute this line after hiding the scrollbar:

     

    #pragma comment(lib"UxTheme.lib")
    if(IsThemeActive()) ::SetWindowTheme(*thisNULL_T("Scrollbar"));

    • Marked as answer by ahmd0 Sunday, May 08, 2011 6:23 PM
    Sunday, May 08, 2011 9:31 AM
  • Thank you, Viorel. You're a genius.

    So from my curiosity, can you explain what exactly does it do?

    And do I need to return the window theme back to whatever it was before I change it to "scrollbar"?

    Sunday, May 08, 2011 6:25 PM
  • I think that the problem is caused by an animation that was started by the system (probably using BeginBufferedAnimation), but was not stopped by ShowScrollBar due to imperfections. Therefore if you hide scrollbars during active animation, then the unexpected scrollbars are drawn at the end of animation. It seems that SetWindowTheme, proposed as workaround, does not forget to stop the animation even if the theme is not affected. Theoretically you should first get the data of the current theme before calling SetWindowTheme. See if it can be done using available functions: http://msdn.microsoft.com/en-us/library/bb773178(VS.85).aspx.

     

    The issue and the sample program can be reported for further resolution to Microsoft Connect: https://connect.microsoft.com.

     

    Sunday, May 08, 2011 6:46 PM
  • Thanks I will try to report it to Connect (if I figure out how to do it).

    From my experimentation I found out that the best workaround seems to be calling this:

    if(IsThemeActive())
    {
     ::SetWindowTheme(hWnd, NULL, NULL);
     ::UpdateWindow(hWnd);
    }

    because calling it with "Scrollbar" seems to mess up visual theme set up for my own controls in that window (in my "real" app). And contrary to logic GetWindowTheme() doesn't act opposite to SetWindowTheme().

    PS. I also just found out that I wasn't using the correct flags while calling RedrawWindow() in my original post. It should've been this:

    ::RedrawWindow(hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_ERASENOW);
    It doesn't solve the original ussue though.
    Sunday, May 08, 2011 7:35 PM