Page 1 of 1

Speed up filling ListiconGadget from thread?

Posted: Sun Sep 12, 2021 12:30 am
by novablue
I am filling a ListiconGadget with a lot of lines so i put it into a seperate thread to not lock up the program, hower this seems to significantly slow it down with thread safe on or off, i also notice that SetGadgetItemColor from a thread is very slow too.

My Times are 2000ms filling from thread and 400ms from the main, and with SetGadgetItemColor commented out i get 600ms from thread and 200ms from main.

is there any way to speed this up?

Code: Select all

Procedure.i Fill(Listicon.i) 
    SendMessage_(GadgetID(Listicon), #WM_SETREDRAW, 0, 0)
    For I = 0 To 5000 
        AddGadgetItem(Listicon, -1, "Test " + I)
        SetGadgetItemColor(Listicon, I, #PB_Gadget_BackColor, #Green) ; Comment out for speedup
    Next
    SendMessage_(GadgetID(Listicon), #WM_SETREDRAW, 1, 0)
EndProcedure

Define MainWindow.i = OpenWindow(#PB_Any, 0, 0, 500, 500, "MainWindow", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
Define Listicon.i   = ListIconGadget(#PB_Any, 0, 0, 500, 500, "Test", 480)

Timer.i  = ElapsedMilliseconds()
Thread.i = CreateThread(@Fill(), Listicon)
While (IsThread(Thread)) : WaitWindowEvent(10) : Wend
Debug ElapsedMilliseconds() - Timer

ClearGadgetItems(Listicon)

Timer.i = ElapsedMilliseconds()
SendMessage_(GadgetID(Listicon), #WM_SETREDRAW, 0, 0)
For I = 0 To 5000 
    AddGadgetItem(Listicon, -1, "Test " + I)
    SetGadgetItemColor(Listicon, I, #PB_Gadget_BackColor, #Green)
Next
SendMessage_(GadgetID(Listicon), #WM_SETREDRAW, 1, 0)
Debug ElapsedMilliseconds() - Timer

Repeat 
	WaitWindowEvent()
ForEver

Re: Speed up filling ListiconGadget from thread?

Posted: Sun Sep 12, 2021 12:40 am
by jacdelad
SetGadgetItemColor is slow, yes.
On Windows: When starting the operation use

Code: Select all

SendMessage_(GadgetID(gadget),#WM_SETREDRAW,0,0)
and after finishing

Code: Select all

SendMessage_(GadgetID(gadget),#WM_SETREDRAW,1,0)
This temporarily disables redrawing and speeds it up a lot.
Another way is to use ownerdrawn listicongadgets. Search the forum, that's been posted somewhere.

Re: Speed up filling ListiconGadget from thread?

Posted: Sun Sep 12, 2021 3:05 am
by Rinzwind
Updating GUI from another thread is not advised in any language. Just FYI.

Re: Speed up filling ListiconGadget from thread?

Posted: Sun Sep 12, 2021 9:25 am
by mk-soft
On Linux and MacOS is not possible to fill from Threads.

Re: Speed up filling ListiconGadget from thread?

Posted: Sun Sep 12, 2021 2:51 pm
by mrv2k
Try a virtual listicon. I can load 38000 items in 27ms. It does add some complications programatically that need to be worked around but it's worth it if you need speed.

Here's an example

Code: Select all

#ItemCount = 5000
#LVSICF_NOINVALIDATEALL = 1
#LVN_ODCACHEHINT = #LVN_FIRST - 13  
  
Global Dim myItems.s(#ItemCount)
  
Procedure WindowCallback(win, msg, wParam, lParam) ; <--------------------> Main Window Callbacks
  
  result = #PB_ProcessPureBasicEvents 
  Select msg 
    Case #WM_NOTIFY 
      *pnmh.NMHDR = lParam 
      *LVCDHeader.NMLVCUSTOMDRAW = lParam
      Select *LVCDHeader\nmcd\dwDrawStage
        Case #CDDS_PREPAINT
          ProcedureReturn #CDRF_NOTIFYITEMDRAW
        Case #CDDS_ITEMPREPAINT
          ; simple example - change text and background colors every other row
          Row = *LVCDHeader\nmcd\dwItemSpec
            *LVCDHeader\clrText = RGB(0, 0, 0)
            *LVCDHeader\clrTextBk = RGB(0, 255, 0)
          ProcedureReturn #CDRF_DODEFAULT
      EndSelect
      Select *pnmh\code 
        Case #LVN_ODCACHEHINT 
          result = 0 
        Case #LVN_GETDISPINFO
          *pnmlvdi.NMLVDISPINFO = lParam 
          If *pnmlvdi\item\mask & #LVIF_TEXT
            Item = *pnmlvdi\item\iItem
            Text$ = myItems(Item)
            *pnmlvdi\item\pszText = @Text$
          EndIf 
      EndSelect 
  EndSelect 
  ProcedureReturn result 
  
EndProcedure

Define MainWindow.i = OpenWindow(#PB_Any, 0, 0, 500, 500, "MainWindow", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered| #LVS_OWNERDATA)
Define Listicon.i   = ListIconGadget(#PB_Any, 0, 0, 500, 500, "Test", 480,#LVS_OWNERDATA)

SetWindowCallback(@WindowCallback()) 

Timer.i = ElapsedMilliseconds()

SendMessage_(GadgetID(Listicon), #WM_SETREDRAW, 0, 0)

SendMessage_(GadgetID(Listicon), #LVM_SETITEMCOUNT, #ItemCount, #LVSICF_NOINVALIDATEALL) 

For I = 0 To #ItemCount
  myItems(I)="test "+ Str(I)
Next

SendMessage_(GadgetID(Listicon), #WM_SETREDRAW, 1, 0)
RedrawWindow_(GadgetID(Listicon),#Null,#Null,#RDW_INVALIDATE)

Debug ElapsedMilliseconds() - Timer

Repeat 
	event=WaitWindowEvent()
Until event=#PB_Event_CloseWindow
Generates the list in 3ms with coloured items.

Rashad has a good bit of code here... viewtopic.php?f=12&t=76419

Re: Speed up filling ListiconGadget from thread?

Posted: Mon Sep 13, 2021 1:08 am
by novablue
Thank you all, i thought i was being smart by putting it into a thread and not lagging the main thread out but i will try a different approach. Virtual Listicon sounds interesting i am surprised nobody made an module for it yet for easier use? :lol: