Fill a ScrollAreaGadget without flickering?

Just starting out? Need help? Post your questions and find answers here.
Lebostein
Addict
Addict
Posts: 807
Joined: Fri Jun 11, 2004 7:07 am

Fill a ScrollAreaGadget without flickering?

Post 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...
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Fill a ScrollAreaGadget without flickering?

Post by srod »

That sounds very odd. Which version of PB / Windows?

Have you got some code you can post which reproduces this?
I may look like a mule, but I'm not a complete ass.
Lebostein
Addict
Addict
Posts: 807
Joined: Fri Jun 11, 2004 7:07 am

Re: Fill a ScrollAreaGadget without delays and flickering?

Post 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
PureLust
Enthusiast
Enthusiast
Posts: 477
Joined: Mon Apr 16, 2007 3:57 am
Location: Germany, NRW

Re: Fill a ScrollAreaGadget without flickering?

Post 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
Last edited by PureLust on Tue Feb 11, 2020 1:25 pm, edited 3 times in total.
[Dynamic-Dialogs] - create complex GUIs the easy way
[DeFlicker] - easily deflicker your resizeable Windows
[WinFX] - Window Effects (incl. 'click-through' Window)
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Fill a ScrollAreaGadget without flickering?

Post 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?
I may look like a mule, but I'm not a complete ass.
User avatar
DK_PETER
Addict
Addict
Posts: 898
Joined: Sat Feb 19, 2011 10:06 am
Location: Denmark
Contact:

Re: Fill a ScrollAreaGadget without flickering?

Post 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...
Current configurations:
Ubuntu 20.04/64 bit - Window 10 64 bit
Intel 6800K, GeForce Gtx 1060, 32 gb ram.
Amd Ryzen 9 5950X, GeForce 3070, 128 gb ram.
Lebostein
Addict
Addict
Posts: 807
Joined: Fri Jun 11, 2004 7:07 am

Re: Fill a ScrollAreaGadget without flickering?

Post 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
Last edited by Lebostein on Tue Feb 11, 2020 1:37 pm, edited 2 times in total.
User avatar
DK_PETER
Addict
Addict
Posts: 898
Joined: Sat Feb 19, 2011 10:06 am
Location: Denmark
Contact:

Re: Fill a ScrollAreaGadget without flickering?

Post 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?
Current configurations:
Ubuntu 20.04/64 bit - Window 10 64 bit
Intel 6800K, GeForce Gtx 1060, 32 gb ram.
Amd Ryzen 9 5950X, GeForce 3070, 128 gb ram.
Lebostein
Addict
Addict
Posts: 807
Joined: Fri Jun 11, 2004 7:07 am

Re: Fill a ScrollAreaGadget without flickering?

Post 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.
PureLust
Enthusiast
Enthusiast
Posts: 477
Joined: Mon Apr 16, 2007 3:57 am
Location: Germany, NRW

Re: Fill a ScrollAreaGadget without flickering?

Post 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
[Dynamic-Dialogs] - create complex GUIs the easy way
[DeFlicker] - easily deflicker your resizeable Windows
[WinFX] - Window Effects (incl. 'click-through' Window)
Lebostein
Addict
Addict
Posts: 807
Joined: Fri Jun 11, 2004 7:07 am

Re: Fill a ScrollAreaGadget without flickering?

Post 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...
PureLust
Enthusiast
Enthusiast
Posts: 477
Joined: Mon Apr 16, 2007 3:57 am
Location: Germany, NRW

Re: Fill a ScrollAreaGadget without flickering?

Post 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
[Dynamic-Dialogs] - create complex GUIs the easy way
[DeFlicker] - easily deflicker your resizeable Windows
[WinFX] - Window Effects (incl. 'click-through' Window)
Lebostein
Addict
Addict
Posts: 807
Joined: Fri Jun 11, 2004 7:07 am

Re: Fill a ScrollAreaGadget without flickering?

Post 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....

Image
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Fill a ScrollAreaGadget without flickering?

Post 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! :wink:
I may look like a mule, but I'm not a complete ass.
PureLust
Enthusiast
Enthusiast
Posts: 477
Joined: Mon Apr 16, 2007 3:57 am
Location: Germany, NRW

Re: Fill a ScrollAreaGadget without flickering?

Post 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. :cry:

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. :?
Last edited by PureLust on Tue Feb 11, 2020 3:43 pm, edited 3 times in total.
[Dynamic-Dialogs] - create complex GUIs the easy way
[DeFlicker] - easily deflicker your resizeable Windows
[WinFX] - Window Effects (incl. 'click-through' Window)
Post Reply