I have created the following example to show an issue I have when scrolling a ContainerControl (and/or Canvas) containing controls.
As you can see there is horrible flicker!
I am performing the move in ValueChanged on the scrollbar āContainerControl11.Left = 0-me.valueā I assume that is the ācorrectā way to move the container around?
I have managed to reduce the flicker to the following using some code here
There is a little flicking here, its hard to pick up with the gif. The ComboBox, RadioButton and Labels are flickering, but everything else is pretty solid.
Does anyone have any more pointers as this just looks nasty.
Ah the sheer joy of OS drawn Win 32 controls
Which is why MS mostly doesnāt use OS drawn control and relies on self drawn controls instead (and there are places in VS 2015 you can still find they do use OS drawn controls and you get the exact same issues)
We donāt use self drawn controls
Not sure if freeing updates and unfreezing them would help or hurt
Something like freeze the update, do the scroll unfreeze the update might alleviate the flickering
Or I could be really wrong on that and it might make it worse
Public Sub FreezeUpdate(extends w as Window)
#if TargetWin32
// Use the WM_SETREDRAW message instead to lock the redraw
// state of the window (note that this can be used for controls as well)
Const WM_SETREDRAW = &hB
call SendMessage( w.Handle, WM_SETREDRAW, 0, 0 )
#endif
End Sub
Public Sub UnfreezeUpdate(extends w as Window)
#if TargetWin32
// Use the WM_SETREDRAW message instead to unlock the redraw
// state of the window (note that this can be used for controls as well)
Const WM_SETREDRAW = &hB
call SendMessage( w.Handle, WM_SETREDRAW, 1, 0 )
#endif
End Sub
I think thatās the exact code I linked above. I used it and it took the flickering from image 1 to image 2. Iām still getting some flicker just on ComboBox, RadioButton and Labels, are they rendered differently somehow?
[quote=308457:@Norman Palardy]Ah the sheer joy of OS drawn Win 32 controls
Which is why MS mostly doesnāt use OS drawn control and relies on self drawn controls instead (and there are places in VS 2015 you can still find they do use OS drawn controls and you get the exact same issues)
We donāt use self drawn controls
Not sure if freeing updates and unfreezing them would help or hurt
Something like freeze the update, do the scroll unfreeze the update might alleviate the flickering
Or I could be really wrong on that and it might make it worse
Public Sub FreezeUpdate(extends w as Window)
#if TargetWin32
// Use the WM_SETREDRAW message instead to lock the redraw
// state of the window (note that this can be used for controls as well)
Const WM_SETREDRAW = &hB
call SendMessage( w.Handle, WM_SETREDRAW, 0, 0 )
#endif
End Sub
Public Sub UnfreezeUpdate(extends w as Window)
#if TargetWin32
// Use the WM_SETREDRAW message instead to unlock the redraw
// state of the window (note that this can be used for controls as well)
Const WM_SETREDRAW = &hB
call SendMessage( w.Handle, WM_SETREDRAW, 1, 0 )
#endif
End Sub
[/quote]
Does this also work for 64bit builds? (you are using TargetWin32)
It may well need to be a different declare for 64 bit Windows
I didnāt check MSDN and just pulled this out of some existing code
So it may need to be written as
Public Sub FreezeUpdate(extends w as Window)
#if TargetWindows
#if Target32Bit
// Use the WM_SETREDRAW message instead to lock the redraw
// state of the window (note that this can be used for controls as well)
Const WM_SETREDRAW = &hB
call SendMessage( w.Handle, WM_SETREDRAW, 0, 0 )
#else
// 64 bit windows declare here
#endif
#endif
End Sub
Public Sub UnfreezeUpdate(extends w as Window)
#if TargetWindows
#if Target32Bit
// Use the WM_SETREDRAW message instead to unlock the redraw
// state of the window (note that this can be used for controls as well)
Const WM_SETREDRAW = &hB
call SendMessage( w.Handle, WM_SETREDRAW, 1, 0 )
#else
// 64 bit windows declare here
#endif
#endif
End Sub
Not in this case
It is the old synonym for TargetWindows
I could literally write
I have to ask, Is it really necessary to scroll the controls? I consider that to be bad UX. Is it possible to group the controls logically onto pages of a tabpanel or something? I personally avoid having to scroll at all costs.
Honestly I wouldnt do this, but it was just a test project to highlight the issue. However just having a control moved on a window resize (which is quite common) would cause the problem, this many controls is just showing it on a higher spec pc.
[quote=308457:@Norman Palardy]Ah the sheer joy of OS drawn Win 32 controls
Which is why MS mostly doesnāt use OS drawn control and relies on self drawn controls instead
[/quote]
I know of no way to reduce flicker to 0 using Windows and OS drawn Win32 controls
Win32 does not double buffer like OS X
VB mostly avoided OS drawn controls and used āself drawn controlsā
As do Word, Excel, Powerpoint etc
As I mentioned the one spot we know of where MS does use them in VS they flicker like mad there too
Long term it would likely need to be a move to WPF, WinForms or Universal or whatever UI kit MS is now saying is the future that will make the Windows UI toolkit fully double buffered so flicker is non-existent
[quote=308724:@Norman Palardy]Iād suggest posting your sample code
It cant hurt to let others kick at it
There may be something else to try once we see code
You never know[/quote]
Hereās a link to the test project. Its super simple code.
You might also see that the āUntitledā label also changes when the scrollbar is moved (see below) from nice to as if its been scaled horizontally a pixel or two.
Public Sub Invalidate(eraseBackground As Boolean = True)
for i as integer = 0 to me.ControlCount() - 1
if me.Control(i) isa RectControl then
RectControl(me.Control(i)).Invalidate
end if
next
End Sub
there does seem to be some weirdness with labels with transparent set to ON so IF This is not a requirement then turn it off on Label1, Label2, Label3
Langue is right, it is no point to use LiveScroll in this case. I would probably set a scrollbar steps so it moves for instance 3 pixels at a time.
There is another thing you can do, especially since I see you are moving the slider pretty fast. Whenever one tries to draw faster than 60 frames a second, bad flicker occurs.
Limit the scroll actions to one per 60th a second. Use ticks with something like this in slider ValueChanged :
static previousTicks as double = Ticks
TimerSlide.Mode = Timer.ModeOff
TimerSlide.Mode = Timer.ModeSingle
if ticks >= previousTicks+1 then
ContainerControl11.Left = 0-me.value
ContainerControl11.Invalidate
previousTicks = Ticks
end if
TimerSlide is here to complete the scroll in case the last change was not taken into account because it was before tick.
I did them all at once Iād be impressed if changing transparency on Label1,2,3 altered all the flickering on the form I was letting you know what happened at each stage. Overall it went back to image 1 in terms of flickering but the number 3 fixed the label issue.
Its surprising how many windows apps (non-uwp) actually use scrolling windows with controls. I guess I have just become immune to spotting them. Hereās an example from a program I regularly use called BeyondCompare, they are using both tabbed controls and scrolling as thereās a lot of options in this program.
I also checked with Inspect and it does use standard windows controls, not custom ones.
[quote=308751:@Michel Bujardet]static previousTicks as double = Ticks
TimerSlide.Mode = Timer.ModeOff
TimerSlide.Mode = Timer.ModeSingle
if ticks >= previousTicks+1 then
ContainerControl11.Left = 0-me.value
ContainerControl11.Invalidate
previousTicks = Ticks
end if[/quote]
This is almost a full fix however Iām still seeing some trailing edge corruption, but not on every control, see here:
While this looks like a good fix it should technically be linked to the refresh rate of the monitor not just 60Hz
Unfortunately the Screen class doesnāt return the Hz of the monitor. So Iāll probably need to dig this out of the registry if this does become my fix for the problem.