Page 1 of 2
Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 10:06 am
by Lebostein
If I clear and fill a ScrollAreaGadget with new gadgets, then it is very slow and flickering. You see the order in which the new gadgets pops up...
Can I change that behaviour? The problem is only on Windows. Mac OS no problems...
Re: Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 11:09 am
by srod
That sounds very odd. Which version of PB / Windows?
Have you got some code you can post which reproduces this?
Re: Fill a ScrollAreaGadget without delays and flickering?
Posted: Tue Feb 11, 2020 12:48 pm
by Lebostein
Windows 10.
Please try it with Mac OS too!
On Mac OS this is very, very fast without any delays and flickering....
Code: Select all
#maxline = 12
#start_combo = 100
#start_string = 200
#max_item = 30
Procedure Rebuild()
For line = 0 To #maxline
If IsGadget(#start_combo + line): FreeGadget(#start_combo + line): EndIf
If IsGadget(#start_string + line): FreeGadget(#start_string + line): EndIf
Next
OpenGadgetList(0)
For line = 0 To #maxline
ComboBoxGadget(#start_combo + line, 10, 10 + line * 25, 230, 22)
For item = 0 To #max_item: AddGadgetItem(#start_combo + line, item, "Blablablup " + Str(item)): Next item
SetGadgetState(#start_combo + line, Random(#max_item))
StringGadget(#start_string + line, 250, 10 + line * 25, 80, 22, "")
Next line
CloseGadgetList()
EndProcedure
If OpenWindow(0, 0, 0, 405, 470, "ScrollAreaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ScrollAreaGadget(0, 10, 10, 390,420, 575, 555, 30)
CloseGadgetList()
ButtonGadget(1, 10, 430, 390,30, "Refresh")
Rebuild()
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
End
Case #PB_Event_Gadget
Select EventGadget()
Case 1: Rebuild()
EndSelect
EndSelect
ForEver
EndIf
Re: Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 1:18 pm
by PureLust
Lebostein wrote:The problem is only on Windows. Mac OS no problems...
Japp, .... it's a known Problem with GUIs, created by PB on Windows.
You could suppress Windows redrawing using handpicked API commands or you can use
[DeFlicker] if you are not confirm with API or try to deflicker your GUI in general and also to keep your source OS independent.
Deflicker by using handpicked API commands:
Code: Select all
EnableExplicit
Procedure Rebuild(Window)
Protected line, x
SendMessage_(WindowID(Window),#WM_SETREDRAW,#False,0) ; <======================
For line = 0 To 10
If IsGadget(100 + line): FreeGadget(100 + line): EndIf
If IsGadget(200 + line): FreeGadget(200 + line): EndIf
Next
OpenGadgetList(0)
For line = 0 To 10
ComboBoxGadget(100 + line, 10, 10 + line * 30, 230, 25)
For x = 0 To 30: AddGadgetItem(100 + line, x, "Blablablup " + Str(x)): Next x
StringGadget(200 + line, 250, 10 + line * 30, 80, 25, "")
SetGadgetState(100 + line, Random(29))
Next line
CloseGadgetList()
SendMessage_(WindowID(0),#WM_SETREDRAW,#True,0) ; <======================
RedrawWindow_(WindowID(0),#Null,#Null,#RDW_INVALIDATE) ; <======================
EndProcedure
If OpenWindow(0, 0, 0, 605, 470, "ScrollAreaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ScrollAreaGadget(0, 10, 10, 390,420, 575, 555, 30)
CloseGadgetList()
ButtonGadget(1, 10, 430, 390,30, "Refresh")
ListIconGadget(2,410,10,100,400, "test", 50)
Rebuild(0)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
End
Case #PB_Event_Gadget
Select EventGadget()
Case 1: Rebuild(0)
EndSelect
EndSelect
ForEver
EndIf
Deflicker by using DeFlicker-Module:
Code: Select all
EnableExplicit
XIncludeFile "..\DeFlicker\Module_DeFlicker.pbi"
Procedure Rebuild(Window)
Protected line, x
DeFlicker_StartResize(Window) ; <======================
For line = 0 To 10
If IsGadget(100 + line): FreeGadget(100 + line): EndIf
If IsGadget(200 + line): FreeGadget(200 + line): EndIf
Next
OpenGadgetList(0)
For line = 0 To 10
ComboBoxGadget(100 + line, 10, 10 + line * 30, 230, 25)
For x = 0 To 30: AddGadgetItem(100 + line, x, "Blablablup " + Str(x)): Next x
StringGadget(200 + line, 250, 10 + line * 30, 80, 25, "")
SetGadgetState(100 + line, Random(29))
Next line
CloseGadgetList()
DeFlicker_EndResize() ; <======================
EndProcedure
If OpenWindow(0, 0, 0, 605, 470, "ScrollAreaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ScrollAreaGadget(0, 10, 10, 390,420, 575, 555, 30)
CloseGadgetList()
ButtonGadget(1, 10, 430, 390,30, "Refresh")
ListIconGadget(2,410,10,100,400, "test", 50)
Rebuild(0)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
End
Case #PB_Event_Gadget
Select EventGadget()
Case 1: Rebuild(0)
EndSelect
EndSelect
ForEver
EndIf
Re: Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 1:20 pm
by srod
I don't have a Mac, but, yes confirmed on Win 7. I can speed it up a little with some use of the #WM_SETREDRAW message and removing all the FreeGadget() calls because they are not needed (PB will free the existing gadgets each time you reuse the gadget#'s), but not a great deal of improvement.
Perhaps rather than keep recreating the gadgets in question, you can instead place them on a container and hide/show the container as required?
Re: Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 1:23 pm
by DK_PETER
@ Lebostein
There is nothing wrong. You have Windows visual effects on. (Animated)
Open Explorer, right click 'Computer'
Select Properties and performance tab.
You have probably everything turned on or give Windows free reigns to
decide itself.
But then again..Not many users fiddles with this...
Re: Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 1:26 pm
by Lebostein
@PureLust: Thanks, that removes the flickering.
But the code remains slow. It seems the "AddGadgetItem" slows down the execution massively.
I have added a timer:
Mac OS:
25 ms (old MacBook from 2012)
Windows 10:
900 ms (i7-3930K 3.20 Ghz, 12 CPU)
Code: Select all
#maxline = 12
#start_combo = 100
#start_string = 200
#max_item = 30
Procedure Rebuild()
start = ElapsedMilliseconds()
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
SendMessage_(WindowID(0),#WM_SETREDRAW,#False,0) ; <======================
CompilerEndIf
For line = 0 To #maxline
If IsGadget(#start_combo + line): FreeGadget(#start_combo + line): EndIf
If IsGadget(#start_string + line): FreeGadget(#start_string + line): EndIf
Next
OpenGadgetList(0)
For line = 0 To #maxline
ComboBoxGadget(#start_combo + line, 10, 10 + line * 25, 230, 22)
For item = 0 To #max_item: AddGadgetItem(#start_combo + line, item, "Blablablup " + Str(item)): Next item
SetGadgetState(#start_combo + line, Random(#max_item))
StringGadget(#start_string + line, 250, 10 + line * 25, 80, 22, "")
Next line
CloseGadgetList()
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
SendMessage_(WindowID(0),#WM_SETREDRAW,#True,0) ; <======================
RedrawWindow_(WindowID(0),#Null,#Null,#RDW_INVALIDATE) ; <======================
CompilerEndIf
SetGadgetText(1, "Press to refresh (" + Str(ElapsedMilliseconds() - start) + ")")
EndProcedure
If OpenWindow(0, 0, 0, 405, 470, "ScrollAreaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ScrollAreaGadget(0, 10, 10, 390,420, 575, 555, 30)
CloseGadgetList()
ButtonGadget(1, 10, 430, 390,30, "Refresh")
Rebuild()
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
End
Case #PB_Event_Gadget
Select EventGadget()
Case 1: Rebuild()
EndSelect
EndSelect
ForEver
EndIf
Re: Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 1:35 pm
by DK_PETER
Lebostein wrote:@PureLust: Thanks, that removes the flickering.
But the code remains slow. It seems the "AddGadgetItem" slows down the execution massively.
I have added a timer:
Mac OS:
25 ms (old MacBook from 2012)
Windows 10:
900 ms
Code: Select all
#maxline = 12
#start_combo = 100
#start_string = 200
#max_item = 30
Procedure Rebuild()
start = ElapsedMilliseconds()
SendMessage_(WindowID(0),#WM_SETREDRAW,#False,0) ; <======================
For line = 0 To #maxline
If IsGadget(#start_combo + line): FreeGadget(#start_combo + line): EndIf
If IsGadget(#start_string + line): FreeGadget(#start_string + line): EndIf
Next
OpenGadgetList(0)
For line = 0 To #maxline
ComboBoxGadget(#start_combo + line, 10, 10 + line * 25, 230, 22)
For item = 0 To #max_item: AddGadgetItem(#start_combo + line, item, "Blablablup " + Str(item)): Next item
SetGadgetState(#start_combo + line, Random(#max_item))
StringGadget(#start_string + line, 250, 10 + line * 25, 80, 22, "")
Next line
CloseGadgetList()
SendMessage_(WindowID(0),#WM_SETREDRAW,#True,0) ; <======================
RedrawWindow_(WindowID(0),#Null,#Null,#RDW_INVALIDATE) ; <======================
SetGadgetText(1, Str(ElapsedMilliseconds() - start))
EndProcedure
If OpenWindow(0, 0, 0, 405, 470, "ScrollAreaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ScrollAreaGadget(0, 10, 10, 390,420, 575, 555, 30)
CloseGadgetList()
ButtonGadget(1, 10, 430, 390,30, "Refresh")
Rebuild()
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
End
Case #PB_Event_Gadget
Select EventGadget()
Case 1: Rebuild()
EndSelect
EndSelect
ForEver
EndIf
If you use disablegadget(#start_combo + line, #True) before adding items
and disablegadget(#start_combo + line, #False) after..
Does that help?
Re: Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 1:41 pm
by Lebostein
DK_PETER wrote:
If you use disablegadget(#start_combo + line, #True) before adding items
and disablegadget(#start_combo + line, #False) after..
Does that help?
No, has no effect.
Re: Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 1:42 pm
by PureLust
Lebostein wrote:@PureLust: Thanks, that removes the flickering.
But the code remains slow. It seems the "AddGadgetItem" slows down the execution massively.
I have added a timer:
Mac OS: 25 ms (old MacBook from 2012)
Windows 10: 900 ms (i7-3930K 3.20 Ghz, 12 CPU)
As srod mentioned before, you could send specific #WM_SETREDRAW Message to suppress the redraw of the ComboBoxGadget.
On my system it will speed it up by a factor of ~3 (~296ms before, ~98ms after).
Code: Select all
#maxline = 12
#start_combo = 100
#start_string = 200
#max_item = 30
Procedure Rebuild()
start = ElapsedMilliseconds()
SendMessage_(WindowID(0),#WM_SETREDRAW,#False,0) ; <======================
For line = 0 To #maxline
If IsGadget(#start_combo + line): FreeGadget(#start_combo + line): EndIf
If IsGadget(#start_string + line): FreeGadget(#start_string + line): EndIf
Next
OpenGadgetList(0)
For line = 0 To #maxline
ComboBoxGadget(#start_combo + line, 10, 10 + line * 25, 230, 22)
SendMessage_(GadgetID(#start_combo + line),#WM_SETREDRAW,#False,0) ; <##########################
For item = 0 To #max_item: AddGadgetItem(#start_combo + line, item, "Blablablup " + Str(item)): Next item
SendMessage_(GadgetID(#start_combo + line),#WM_SETREDRAW,#True,0) ; <##########################
SetGadgetState(#start_combo + line, Random(#max_item))
StringGadget(#start_string + line, 250, 10 + line * 25, 80, 22, "")
Next line
CloseGadgetList()
SendMessage_(WindowID(0),#WM_SETREDRAW,#True,0) ; <======================
RedrawWindow_(WindowID(0),#Null,#Null,#RDW_INVALIDATE) ; <======================
SetGadgetText(1, Str(ElapsedMilliseconds() - start))
EndProcedure
If OpenWindow(0, 0, 0, 405, 470, "ScrollAreaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ScrollAreaGadget(0, 10, 10, 390,420, 575, 555, 30)
CloseGadgetList()
ButtonGadget(1, 10, 430, 390,30, "Refresh")
Rebuild()
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
End
Case #PB_Event_Gadget
Select EventGadget()
Case 1: Rebuild()
EndSelect
EndSelect
ForEver
EndIf
Re: Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 1:45 pm
by Lebostein
@PureLust: Thanks, that speeds up the execution. I see 320 ms now instead of 900. But 300 ms compared to 25 ms is still slow...
I wonder why Mac OS can handle that redraw things automatically...
Re: Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 2:10 pm
by PureLust
Lebostein wrote:@PureLust: Thanks, that speeds up the execution. I see 320 ms now instead of 900. But 300 ms compared to 25 ms is still slow...
I wonder why Mac OS can handle that redraw things automatically...
Speed seems to be a windows issue and not related to PB.
If you add items directly trough API, it will not speed up:
Code: Select all
#maxline = 12
#start_combo = 100
#start_string = 200
#max_item = 30
Procedure Rebuild()
start = ElapsedMilliseconds()
SendMessage_(WindowID(0),#WM_SETREDRAW,#False,0) ; <======================
For line = 0 To #maxline
If IsGadget(#start_combo + line): FreeGadget(#start_combo + line): EndIf
If IsGadget(#start_string + line): FreeGadget(#start_string + line): EndIf
Next
OpenGadgetList(0)
For line = 0 To #maxline
ComboBoxGadget(#start_combo + line, 10, 10 + line * 25, 230, 22)
SendMessage_(GadgetID(#start_combo + line),#WM_SETREDRAW,#False,0) ; <##########################
For item = 0 To #max_item:
SendMessage_(GadgetID(#start_combo + line), #CB_ADDSTRING, 0, "Blablablup " + Str(item)) ; <*****************************
;AddGadgetItem(#start_combo + line, item, "Blablablup " + Str(item))
Next item
SendMessage_(GadgetID(#start_combo + line),#WM_SETREDRAW,#True,0) ; <##########################
SetGadgetState(#start_combo + line, Random(#max_item))
StringGadget(#start_string + line, 250, 10 + line * 25, 80, 22, "")
Next line
CloseGadgetList()
SendMessage_(WindowID(0),#WM_SETREDRAW,#True,0) ; <======================
RedrawWindow_(WindowID(0),#Null,#Null,#RDW_INVALIDATE) ; <======================
SetGadgetText(1, Str(ElapsedMilliseconds() - start))
EndProcedure
If OpenWindow(0, 0, 0, 405, 470, "ScrollAreaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ScrollAreaGadget(0, 10, 10, 390,420, 575, 555, 30)
CloseGadgetList()
ButtonGadget(1, 10, 430, 390,30, "Refresh")
Rebuild()
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
End
Case #PB_Event_Gadget
Select EventGadget()
Case 1: Rebuild()
EndSelect
EndSelect
ForEver
EndIf
Re: Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 2:26 pm
by Lebostein
Can I copy/duplicate a filled ComboGadget with window-API? So I can fill this thing one time an copy it as often as I need to...
I need it for a filter system like the intelligent playlist in iTunes (see picture). So every line is a condition build with 2 ComboGadgets and a string gadget with dozens of properties and operators. But every ComboGadget in each line has the same values....

Re: Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 2:51 pm
by srod
Closest thing to doing that would be an owner-drawn combo without the #CBS_HASSTRINGS styles. In this case you would simply draw the text yourself, taking the text from your own data structures. Quite a bit of work involved in this.
How about the following where we create the combo's just once and then simply repopulate everytime you hit the rebuild button. Together with some #WM_SETREDRAW's seems to speed up massively here. The original #WM_SETREDRAW was directed at the main window. It should instead be directed at the ScrollArea's 'inner panel' which I have corrected.
Code: Select all
Procedure Rebuild()
hWnd = GetParent_(GadgetID(#start_combo))
SendMessage_(hWnd,#WM_SETREDRAW,#False,0) ; <======================
For line = 0 To #maxline
SendMessage_(GadgetID(#start_combo + line),#WM_SETREDRAW,#False,0) ; <##########################
For item = 0 To #max_item: AddGadgetItem(#start_combo + line, item, "Blablablup " + Str(item)): Next item
SendMessage_(GadgetID(#start_combo + line),#WM_SETREDRAW,#True,0) ; <##########################
SetGadgetState(#start_combo + line, Random(#max_item))
Next
SendMessage_(hWnd,#WM_SETREDRAW,#True,0) ; <======================
RedrawWindow_(hWnd,#Null,#Null,#RDW_INVALIDATE) ; <======================
EndProcedure
If OpenWindow(0, 0, 0, 405, 470, "ScrollAreaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ScrollAreaGadget(0, 10, 10, 390,420, 575, 555, 30)
For line = 0 To #maxline
ComboBoxGadget(#start_combo + line, 10, 10 + line * 25, 230, 22)
StringGadget(#start_string + line, 250, 10 + line * 25, 80, 22, "")
Next
CloseGadgetList()
ButtonGadget(1, 10, 430, 390,30, "Refresh")
Rebuild()
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
End
Case #PB_Event_Gadget
Select EventGadget()
Case 1: Rebuild()
EndSelect
EndSelect
ForEver
EndIf
If this is not enough then your next step might be to intercept the #CBN_DROPDOWN notification and populate the combo box in question at this point only (if the combo is empty). That is, do not populate the controls all at once, only when needed.
If this is not enough then I refer you back to my original reply regarding using a container gadget!

Re: Fill a ScrollAreaGadget without flickering?
Posted: Tue Feb 11, 2020 3:20 pm
by PureLust
srod wrote:How about the following where we create the combo's just once and then simply repopulate everytime you hit the rebuild button. Together with some #WM_SETREDRAW's seems to speed up massively here.
Wow .... that speeded it up A LOT . . . but . . . you missed to clear the GadgetItems first, so you add more and more items each time.
But ... if you clear the GadgetItem List first, this will eat up a lot of time again.

Code: Select all
ClearGadgetItems(#start_combo + line)
[Edit] Doesn't seems to be ClearGadgetItems() that eats up the time (placed it outside the Timecount-Loop). But it increases the time, needed to add the next (first) 30 items a lot.
I wonder, why it's so much faster to add 30 items to an already filled ItemList than it takes to add them to an empty List.
