Jump to content

Anyone can speed up/optimize this Virtual Listview?


qsek
 Share

Recommended Posts

I am experimenting lately with Virtual Listviews and i am wondering if there is a possibility to make repeated mass updates of many LV items (Item Color, value, icon) more CPU friendly and faster.

Would subclassing be an option or using a custom external Dll?

This is what i got so far:

;~ #include <_GUICtrlListView.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#Include <GuiImageList.au3>
#include <GUIConstants.au3>

Global $switch = 0
Global $tTextBufferV, $sSeparatorV,$aArrayV[1]

$sTextBuff = "char[100]"
If Execute("@Unicode") Then $sTextBuff = "w" & $sTextBuff
$tTextBufferV = DllStructCreate($sTextBuff)
Global $iNum = 23
$change = 23
$width = 4

Dim $aArrayV[$iNum][$width+1]


#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Form1", 750, 590, 191, 113)

        $hImage = _GUIImageList_Create(16,16,5)

        $I_blank    = _GUIImageList_AddIcon($hImage, @SystemDir & "\shell32.dll", 110)
        $I_comstar  = _GUIImageList_AddIcon($hImage, @SystemDir & "\shell32.dll", 131)
        
;~ Global const $LVS_OWNERDATA=0x1000
$ListView1 = GUICtrlCreateListView("ID|1    |2    |3    |4    ", 2, 120, 363, 431, $LVS_SHOWSELALWAYS + $LVS_OWNERDATA, BitOR($LVS_EX_FULLROWSELECT, $WS_EX_CLIENTEDGE, $LVS_EX_DOUBLEBUFFER, $LVS_EX_GRIDLINES, $LVS_EX_TRACKSELECT, $LVS_EX_SUBITEMIMAGES))
$hhLV = GUICtrlGetHandle($ListView1)
GUICtrlSendMsg(-1, 0x101E, 0, 100)
GUICtrlSendMsg($ListView1, $LVM_SETITEMCOUNT, $iNum, 0) ;;set total item count - necessary for virtual lv
_SendMessage($hhLV, $LVM_SETIMAGELIST, $LVSIL_SMALL, $hImage, 0, "wparam", "hwnd", "hwnd")


$ListView2 = GUICtrlCreateListView("ID|1    |2    |3    |4    ", 121*3+15, 120, 121*3, 431, $LVS_SHOWSELALWAYS + $LVS_OWNERDATA, BitOR($LVS_EX_FULLROWSELECT, $WS_EX_CLIENTEDGE, $LVS_EX_DOUBLEBUFFER, $LVS_EX_GRIDLINES, $LVS_EX_TRACKSELECT, $LVS_EX_SUBITEMIMAGES))
$hhLV2 = GUICtrlGetHandle($ListView2)
GUICtrlSendMsg(-1, 0x101E, 0, 100)
GUICtrlSendMsg($ListView2, $LVM_SETITEMCOUNT, $iNum, 0) ;;set total item count - necessary for virtual lv
_SendMessage($hhLV2, $LVM_SETIMAGELIST, $LVSIL_SMALL, $hImage, 0, "wparam", "hwnd", "hwnd")

GUISetState(@SW_SHOW)

GUIRegisterMsg($WM_NOTIFY,"_UDF_WM_NOTIFY")
#EndRegion ### START Koda GUI section ### Form=

$sec = 0
While 1
    If Not ($sec = @SEC) Then ; Do every second
        
        $switch = Not $switch

        For $ei = 0 To $change-1 Step 1;$iNum-1
            $aArrayV[$ei][0] += 2
            For $ej = 1 To $width Step 1
                $aArrayV[$ei][$ej] += 1
            Next
            
            Local $tRect = DllStructCreate($tagRECT)
            DllStructSetData($tRect, "Left", 3)
            _SendMessage($hhLV, $LVM_GETITEMRECT, $ei, DllStructGetPtr($tRect), 0, "wparam", "ptr")
            _WinAPI_InvalidateRect($hhLV,$tRect,false)
            
;~          Local $tRect = DllStructCreate($tagRECT)
;~          DllStructSetData($tRect, "Left", 3)
            _SendMessage($hhLV2, $LVM_GETITEMRECT, $ei, DllStructGetPtr($tRect), 0, "wparam", "ptr")
            
            _WinAPI_InvalidateRect($hhLV2,$tRect,false)
            ; Update one Item after another
        Next
        
;~      _WinAPI_InvalidateRect($hhLV,0,false)
;~      _WinAPI_InvalidateRect($hhLV2,0,false)
        ; Update all Items even if there is no change
        $sec = @SEC
    EndIf


    $nMsg = GUIGetMsg()
    
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit

    EndSwitch
    


WEnd


Func _startup($iNumF)
        
    $width = 6
    Local $aStart[$iNum][$width]
    for $i = 0 to $iNum-1
        $aStart[$i][0] = _randString(Random(4,14,1),Asc("A"),Asc("z"))
        for $j = 1 to $width-1
            $aStart[$i][$j] = $i & "|" & $j
        next
    next

    Return $aStart
EndFunc   ;==>_startup



Func _randString($_end = 5, $chrS = 65, $chrE = 90)
    Local $str = ""
    For $i = 1 To $_end
        $str &= Chr(Random($chrS,$chrE,1))
    Next
    Return $str

EndFunc


Func _UDF_WM_NOTIFY($hWnd, $Msg, $wParam, $lParam)
    Local  $i, $j, $tNMLVDISPINFO, $text, $textlen, $maxlen
    ;;$WM_NOTIFY = 0x004E

;~     If $Msg <> 0x004E Then Return 

    Local $tNMHDR = DllStructCreate("hwnd hwndfrom;int idfrom;int code", $lParam)
    Local $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hwndfrom"))
    Local $iCode = DllStructGetData($tNMHDR, "code")
;~  ConsoleWrite(Hex($Msg) &", "& $iCode& @CRLF)
    Switch $hWndFrom
        Case $hhLV,$hhLV2
            Switch $iCode
                Case -150, -177 ;;$LVN_GETDISPINFOA = -150, $LVN_GETDISPINFOW = -177
                    ;;give requested items one by one (kinda slow if a lot of items are visible at the same time)

                    $tNMLVDISPINFO = DllStructCreate("hwnd hwndfrom;int idfrom;int code;" & _
                            "uint mask;int item;int subitem;uint state;uint statemask;ptr text;int textmax;int image;dword lparam;int;uint[5]", $lParam)

    ;~                 If BitAND(DllStructGetData($tNMLVDISPINFO, "mask"), $LVIF_TEXT) Then
                        $i = DllStructGetData($tNMLVDISPINFO, "item")
    ;~                  ConsoleWrite($i&" =? "&DllStructGetData($tNMLVDISPINFO, "item") & @CRLF)
                        $j = DllStructGetData($tNMLVDISPINFO, "subitem")
    ;~                  ConsoleWrite($i&","&$j-1 & @CRLF)


                        $text = $aArrayV[$i][$j]

                        

                        $textlen = StringLen($text)
                        $maxlen = DllStructGetSize($tTextBufferV)
    ;~                     If Execute("@Unicode") Then $maxlen = $maxlen / 2
                        If $textlen > $maxlen - 1 Then $text = StringLeft($text, $maxlen - 1)

                        DllStructSetData($tTextBufferV, 1, $text)
                        DllStructSetData($tNMLVDISPINFO, "textmax", $textlen)
                        DllStructSetData($tNMLVDISPINFO, "text", DllStructGetPtr($tTextBufferV))
                        If (Not $j Or $i = 4) And $i < $change Then DllStructSetData($tNMLVDISPINFO, "image", Not($switch)+0)
    ;~                 EndIf
                Case $NM_CUSTOMDRAW
                    
    ;~              Return
                    Local $tCustDraw = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
                    Local $iDrawStage, $iItem, $iSubitem, $hDC, $tRect
                    $iDrawStage = DllStructGetData($tCustDraw, 'dwDrawStage')

                
;~                  ConsoleWrite("customdraw item("&DllStructGetData($tCustDraw, 'dwItemSpec')&"),drawstage("&$CDDS_ITEMPREPAINT&"):"&$iDrawStage & @CRLF)

                    Switch $iDrawStage
                        Case $CDDS_PREPAINT ; Stage 0: something is about to be drawned
                            Return $CDRF_NOTIFYITEMDRAW ; We want to be informed if an Item is about to be drawned
                        Case $CDDS_ITEMPREPAINT ; Stage 1: an Item is about to be drawned
;~                          Return $CDRF_NOTIFYITEMDRAW; We want to be informed if an SUBitem is about to be drawned
;~                      Case BitOR($CDDS_ITEMPREPAINT, $CDDS_SUBITEM); Stage 2: an SUBitem is about to be drawned

;~                          ConsoleWrite("Subitem" & @CRLF)
                            $iItem = DllStructGetData($tCustDraw, 'dwItemSpec')
;~                          $iSubitem = DllStructGetData($tCustDraw, 'iSubItem')
;~                          ConsoleWrite($iItem&","&$iSubitem & @CRLF)
;~                          If $iSubitem > 1 Then Return
                                ;#### $iSlot = _GUICtrlListView_GetItemParam($nID, $iItem) ######
;~                              $tItem = DllStructCreate($tagLVITEM)
;~                              DllStructSetData($tItem, "Mask", $LVIF_PARAM)
;~                              DllStructSetData($tItem, "Item", $iItem)
;~                              $pItem = DllStructGetPtr($tItem)
;~                              GUICtrlSendMsg($wParam, $LVM_GETITEMW, 0, $pItem)
;~                              $iSlot = DllStructGetData($tItem, "Param")
;~                              ConsoleWrite("$iSlot: "&$iSlot & @CRLF)
                                ;#############
;~                          ConsoleWrite($iSlot & @CRLF)
;~                          If $PlistArr[$iSlot][0] == "" Or Not ($PlistArr[$iSlot][1] = $iItem) Then Return ; no custom info for this subitem, no change

                            If $switch Or $iItem >= $change Then
                                Return 1
                                DllStructSetData($tCustDraw, 'clrText', 0x000000)
                                DllStructSetData($tCustDraw, 'clrTextBk', 0xFFFFFF)
                            Else
    ;~                          Return $CDRF_Newfont
                                DllStructSetData($tCustDraw, 'clrText', 0xFFFFFF)
                                DllStructSetData($tCustDraw, 'clrTextBk', 0x000000)
    ;~                                      _SetItemCol($nID, $hDC, $tCustDraw, $iItem, $iSubitem); Obsolete, wird alles hier erledigt
                            EndIf
                            Return 1
                    EndSwitch
            EndSwitch
    EndSwitch



    Return 

EndFunc
Teamspeak 3 User Viewer - Quick and functional TS3 Query script, which shows online users.Cached Screenshot Deleter - Deletes older Fraps Screenshots if they exceed a specified limit.Unresolved Topics:Intercept and modify dragdrop text behaviour in scite
Link to comment
Share on other sites

It seems like there is nothing to subclass. The $WM_NOTIFY is send to the parent GUI window so unless you want to do it in much low-level than you want it seems like all you need is a few sleeps here and there to reduce CPU usage and speeding it up by calling _WinAPI_InvalidateRect($hhLV, 0, False) and _WinAPI_InvalidateRect($hhLV2, 0, False) each second and manipulate the specific items and sub-items in the handler. It'll make more sense to put the loop inside an adlib function in my opinion. You can subclass the control and handle the WM_PAINT in your own way but it'd be much more painful than the way it's now. >_

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...