Sign in to follow this  
Followers 0

_GUICtrlListView_CreateArray() - Create an array from a ListView.


22 posts in this topic

Posted (edited)

For those who use ListViews and wish to call a Function to grab the contents of the ListView into a 2D array, then _GUICtrlListView_CreateArray() is for you. It will Return an array with the contents of the ListView inc. the number of rows, columns & column names. Simply run the Example to get an idea of the output. Thanks.

Function:

; #FUNCTION# ====================================================================================================================
; Name ..........: _GUICtrlListView_CreateArray
; Description ...: Creates a 2-dimensional array from a listview.
; Syntax ........: _GUICtrlListView_CreateArray($hListView[, $sDelimeter = '|'])
; Parameters ....: $hListView           - Control ID/Handle to the control
;                  $sDelimeter          - [optional] One or more characters to use as delimiters (case sensitive). Default is '|'.
; Return values .: Success - The array returned is two-dimensional and is made up of the following:
;                                $aArray[0][0] = Number of rows
;                                $aArray[0][1] = Number of columns
;                                $aArray[0][2] = Delimited string of the column name(s) e.g. Column 1|Column 2|Column 3|Column nth

;                                $aArray[1][0] = 1st row, 1st column
;                                $aArray[1][1] = 1st row, 2nd column
;                                $aArray[1][2] = 1st row, 3rd column
;                                $aArray[n][0] = nth row, 1st column
;                                $aArray[n][1] = nth row, 2nd column
;                                $aArray[n][2] = nth row, 3rd column
; Author ........: guinness
; Remarks .......: GUICtrlListView.au3 should be included.
; Example .......: Yes
; ===============================================================================================================================
Func _GUICtrlListView_CreateArray($hListView, $sDelimeter = '|')
    Local $iColumnCount = _GUICtrlListView_GetColumnCount($hListView), $iDim = 0, $iItemCount = _GUICtrlListView_GetItemCount($hListView)
    If $iColumnCount < 3 Then
        $iDim = 3 - $iColumnCount
    EndIf
    If $sDelimeter = Default Then
        $sDelimeter = '|'
    EndIf

    Local $aColumns = 0, $aReturn[$iItemCount + 1][$iColumnCount + $iDim] = [[$iItemCount, $iColumnCount, '']]
    For $i = 0 To $iColumnCount - 1
        $aColumns = _GUICtrlListView_GetColumn($hListView, $i)
        $aReturn[0][2] &= $aColumns[5] & $sDelimeter
    Next
    $aReturn[0][2] = StringTrimRight($aReturn[0][2], StringLen($sDelimeter))

    For $i = 0 To $iItemCount - 1
        For $j = 0 To $iColumnCount - 1
            $aReturn[$i + 1][$j] = _GUICtrlListView_GetItemText($hListView, $i, $j)
        Next
    Next
    Return SetError(Number($aReturn[0][0] = 0), 0, $aReturn)
EndFunc   ;==>_GUICtrlListView_CreateArray
Example use of Function:

#include <Array.au3> ; Required only for _ArrayDisplay().
#include <GUIConstantsEx.au3>
#include <GUIListView.au3>
#include <WindowsConstants.au3>

Example()

Func Example()
    Local $iWidth = 600, $iHeight = 400, $iListView = 0
    Local $hGUI = GUICreate('_GUICtrlListView_CreateArray()', $iWidth, $iHeight, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX))

    _CreateListView($hGUI, $iListView)

    Local $iGetArray = GUICtrlCreateButton('Get Array', $iWidth - 90, $iHeight - 28, 85, 25)
    GUICtrlSetResizing(-1, $GUI_DOCKRIGHT + $GUI_DOCKSIZE + $GUI_DOCKBOTTOM)

    Local $iRefresh = GUICtrlCreateButton('Refresh', $iWidth - 180, $iHeight - 28, 85, 25)
    GUICtrlSetResizing(-1, $GUI_DOCKRIGHT + $GUI_DOCKSIZE + $GUI_DOCKBOTTOM)

    GUISetState(@SW_SHOW, $hGUI)

    Local $aReturn = 0, $aStringSplit = 0
    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $iGetArray
                $aReturn = _GUICtrlListView_CreateArray($iListView, Default) ; Use | as the default delimeter.
                _ArrayDisplay($aReturn, '_GUICtrlListView_CreateArray() array.')

                $aStringSplit = StringSplit($aReturn[0][2], '|')
                _ArrayDisplay($aStringSplit, 'StringSplit() to retrieve column names.')

            Case $iRefresh
                GUICtrlDelete($iListView)
                _CreateListView($hGUI, $iListView)

        EndSwitch
    WEnd
    GUIDelete($hGUI)
EndFunc   ;==>Example

Func _CreateListView($hGUI, ByRef $iListView) ; Thanks to AZJIO for this function.
    Local $aClientSize = WinGetClientSize($hGUI)
    $iListView = GUICtrlCreateListView('', 0, 0, $aClientSize[0], $aClientSize[1] - 30)
    GUICtrlSetResizing($iListView, $GUI_DOCKBORDERS)
    Sleep(250)

    Local $iColumns = Random(1, 5, 1)
    __ListViewFill($iListView, $iColumns, Random(25, 100, 1)) ; Fill the ListView with Random data.
    For $i = 0 To $iColumns
        _GUICtrlListView_SetColumnWidth($iListView, $i, $LVSCW_AUTOSIZE)
        _GUICtrlListView_SetColumnWidth($iListView, $i, $LVSCW_AUTOSIZE_USEHEADER)
    Next
EndFunc   ;==>_CreateListView

Func __ListViewFill($hListView, $iColumns, $iRows) ; Required only for the Example.
    If Not IsHWnd($hListView) Then
        $hListView = GUICtrlGetHandle($hListView)
    EndIf
    Local $fIsCheckboxesStyle = (BitAND(_GUICtrlListView_GetExtendedListViewStyle($hListView), $LVS_EX_CHECKBOXES) = $LVS_EX_CHECKBOXES)

    _GUICtrlListView_BeginUpdate($hListView)
    For $i = 0 To $iColumns - 1
        _GUICtrlListView_InsertColumn($hListView, $i, 'Column ' & $i + 1, 50)
        _GUICtrlListView_SetColumnWidth($hListView, $i - 1, -2)
    Next
    For $i = 0 To $iRows - 1
        _GUICtrlListView_AddItem($hListView, 'Row ' & $i + 1 & ': Col 1', $i)
        If Random(0, 1, 1) And $fIsCheckboxesStyle Then
            _GUICtrlListView_SetItemChecked($hListView, $i)
        EndIf
        For $j = 1 To $iColumns
            _GUICtrlListView_AddSubItem($hListView, $i, 'Row ' & $i + 1 & ': Col ' & $j + 1, $j)
        Next
    Next
    _GUICtrlListView_EndUpdate($hListView)
EndFunc   ;==>__ListViewFill
Edited by guinness
mLipok and JScript like this

Share this post


Link to post
Share on other sites



Posted

guinness,

Nice. :huh2:

M23

Share this post


Link to post
Share on other sites

Posted

Thank Melba :huh2:

Share this post


Link to post
Share on other sites

Posted

guinness,

I was just looking through you signature (after reading a recent post you replied to) and found this topic. to do the same thing. Upon examining and comparing our methods it seems the only real differences are my function doesn't have error checking and I dynamically build the array instead of initial size declaration. Less the error checking, I assume declaring the array size initially has better performance than performing a Ubound over and over. Would you agree?

Share this post


Link to post
Share on other sites

Posted (edited)

In your example ReDim is the real issue with performance (look at _ReDim in my signature) so since you know the number of rows anyway it's best just to initial the array at the start of the function. I've also read that the larger the array becomes the slower Ubound is, though we're talking ms. Another point is some variables aren't declared in Local scope and you're declaring a variable inside a loop which can affect performance too.

I wonder what the difference in time is? I will check this evening.

Edited by guinness

Share this post


Link to post
Share on other sites

Posted (edited)

With 5000 items the results were:

Mine: 1313.33962550961

Yours: 13802.8888616261

Mine: 1404.9440669193

Yours: 13556.6254318947

But on a ListView with 100 it wasn't worth documenting. Edited by guinness

Share this post


Link to post
Share on other sites

Posted

Cool, thanks for the knowledge and benchmarks.

Share this post


Link to post
Share on other sites

Posted

No problem, thanks for pointing out your function to me. I remember your project SpeeDBurner come to think of it, believe it or not it was something I used when I started out with AutoIt.

Share this post


Link to post
Share on other sites

Posted

This is fantastic. I'm using ListViews to hold the results of WMI queries, and this is the ideal way to get them out to a spreadsheet. Thanks for giving this to the community!

Share this post


Link to post
Share on other sites

Posted

No problem. Thanks for the compliment.

Share this post


Link to post
Share on other sites

Posted

5 stars from me! Thank you my friend.

:thumbsup:

JS

Share this post


Link to post
Share on other sites

Posted (edited)

This can be shorter

$sIndex = _GUICtrlListView_GetItemText($hListView, $A)
$aReturn[$A + 1][0] = $sIndex

5 stars. Useful thing

Edited by AZJIO

Share this post


Link to post
Share on other sites

Posted

I will optimise the function today as i've learnt a lot in the last year.

Share this post


Link to post
Share on other sites

Posted (edited)

I've updated the function as promised and optimised the code greatly. Now there are fewer lines and no more unnecessary variables. See the original post for more details.

Edit: Oh, and the times mentioned in post #6 have been decreased by 120%!

Edited by guinness

Share this post


Link to post
Share on other sites

Posted (edited)

#include <Array.au3> ; Required only for _ArrayDisplay().
#include <GUIConstantsEx.au3>
#include <GUIListView.au3>
#include <WindowsConstants.au3>
#include <_GUICtrlListView_CreateArray.au3>

Example()

Func Example()
    Local $iWidth = 600, $iHeight = 400, $iListView
    Local $hGUI = GUICreate('_GUICtrlListView_CreateArray()', $iWidth, $iHeight, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX))

    _CreateListView($hGUI, $iListView)

    Local $iGetArray = GUICtrlCreateButton('Get Array', $iWidth - 120, $iHeight - 28, 115, 27)
    GUICtrlSetResizing(-1, $GUI_DOCKRIGHT + $GUI_DOCKSIZE + $GUI_DOCKBOTTOM)

    Local $iRefresh = GUICtrlCreateButton('Refresh', $iWidth - 240, $iHeight - 28, 115, 27)
    GUICtrlSetResizing(-1, $GUI_DOCKRIGHT + $GUI_DOCKSIZE + $GUI_DOCKBOTTOM)

    GUISetState(@SW_SHOW, $hGUI)

    Local $aReturn = 0, $aStringSplit = 0
    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $iGetArray
                $aReturn = _GUICtrlListView_CreateArray($iListView, Default) ; Use | as the default delimeter.
                _ArrayDisplay($aReturn, '_GUICtrlListView_CreateArray() array.')

                $aStringSplit = StringSplit($aReturn[0][2], '|')
                _ArrayDisplay($aStringSplit, 'StringSplit() to retrieve column names.')

            Case $iRefresh
                GUICtrlDelete($iListView)
                _CreateListView($hGUI, $iListView)

        EndSwitch
    WEnd
    GUIDelete($hGUI)
EndFunc

Func _CreateListView($hGUI, ByRef $iListView)
    $ClientSize = WinGetClientSize($hGUI)
    $iListView = GUICtrlCreateListView('', 0, 0, $ClientSize[0], $ClientSize[1] - 30)
    GUICtrlSetResizing($iListView, $GUI_DOCKBORDERS)
    Sleep(250)

    $iCol = Random(1, 5, 1)
    __ListViewFill($iListView, $iCol, Random(25, 100, 1)) ; Fill the ListView with Random data.
    For $i = 0 To $iCol
        GUICtrlSendMsg($iListView, $LVM_SETCOLUMNWIDTH, $i, -1)
        GUICtrlSendMsg($iListView, $LVM_SETCOLUMNWIDTH, $i, -2)
    Next
EndFunc

Func __ListViewFill($hListView, $iColumns, $iRows) ; Required only for the Example.
    If Not IsHWnd($hListView) Then
        $hListView = GUICtrlGetHandle($hListView)
    EndIf
    Local $fIsCheckboxesStyle = (BitAND(_GUICtrlListView_GetExtendedListViewStyle($hListView), $LVS_EX_CHECKBOXES) = $LVS_EX_CHECKBOXES)

    _GUICtrlListView_BeginUpdate($hListView)
    For $i = 0 To $iColumns - 1
        _GUICtrlListView_InsertColumn($hListView, $i, 'Column ' & $i + 1, 50)
        _GUICtrlListView_SetColumnWidth($hListView, $i - 1, -2)
    Next
    For $i = 0 To $iRows - 1
        _GUICtrlListView_AddItem($hListView, 'Row ' & $i + 1 & ': Col 1', $i)
        If Random(0, 1, 1) And $fIsCheckboxesStyle Then
            _GUICtrlListView_SetItemChecked($hListView, $i)
        EndIf
        For $j = 1 To $iColumns
            _GUICtrlListView_AddSubItem($hListView, $i, 'Row ' & $i + 1 & ': Col ' & $j + 1, $j)
        Next
    Next
    _GUICtrlListView_EndUpdate($hListView)
EndFunc

Edited by AZJIO

Share this post


Link to post
Share on other sites

Posted

Thanks AZJIO, I updated the example in the first post with your improvement to re-creating the ListView. My version was just a quick 'hack' as I was in a rush to upload the function and example.

Share this post


Link to post
Share on other sites

Posted

Hello,

Just a detail in the header of the script.

$aArray[0][3] = Delimited string of the column name(s) e.g. Column 1|Column 2|Column 3|Column nth

should be

$aArray[0][2] = Delimited string of the column name(s) e.g. Column 1|Column 2|Column 3|Column nth

Thank you

Share this post


Link to post
Share on other sites

Posted

Funny, I was just thinking about this function and whether I should add it to the UDFs, but that's a different story. Thanks I will fix it.

Share this post


Link to post
Share on other sites

Posted

I was messing around with this and I noticed that replacing

$aReturn[$i + 1][$j] = _GUICtrlListView_GetItemText($hListView, $i, $j)

with

$aReturn[$i + 1][$j] = ControlListView($hGUI, '', $hListView, 'GetText', $i, $j)

seems to speed this up a bit.

Unfortunately I could not get it to work without having to put the window handle in there.

Share this post


Link to post
Share on other sites

Posted (edited)

http://autoit-script.ru/index.php/topic,12724.15.html

#include <WinAPI.au3>
#include <Array.au3>

$hGui = GUICreate('Test', 400, 300)
$iListView = GUICtrlCreateListView('Line     |Data', 2, 2, 394, 268)
; $iListView = GUICtrlCreateListView('Line', 2, 2, 394, 268)
$hListView = GUICtrlGetHandle(-1)
; $hListView = $iListView
For $i = 1 To 1000
	GUICtrlCreateListViewItem('Line ' & $i & '|' & Random(1000, 9999, 1), $iListView)
	; GUICtrlCreateListViewItem('Line '&$i, $iListView)
Next
GUISetState()

$hTimer = TimerInit()
$aReturn = _GUICtrlListView_GetAllTextToArray($hListView)
$extended = @extended
If @error < 0 Then Exit MsgBox(0, 'Message', 'List empty')
$sTime = Round(TimerDiff($hTimer)) & ' ms'
; MsgBox(262144, 'Information', _
; "Items: " & _WinAPI_LoWord($extended) & @LF & _
; "Columns: " & _WinAPI_HiWord($extended))
_ArrayDisplay($aReturn, $sTime)

Func _GUICtrlListView_GetAllTextToArray($hListView)
	If Not IsHWnd($hListView) Then
		$hListView = GUICtrlGetHandle($hListView)
		If Not IsHWnd($hListView) Then Return SetError(1, 0, 0)
	EndIf
	Local $hWin, $iItems, $iSubitems
	$hWin = _WinAPI_GetParent($hListView)
	If Not $hWin Then Return SetError(2, 0, 0)
	$iItems = ControlListView($hWin, '', $hListView, 'GetItemCount')
	If Not $iItems Then Return SetError(-1, 0, 0)
	$iSubitems = ControlListView($hWin, '', $hListView, 'GetSubItemCount')
	; If Not $iSubitems Then Return SetError(-2, 0, 0)
	If Not $iSubitems Then $iSubitems = 1
	Local $aReturn[$iItems][$iSubitems] = [[$iItems]]
	; For $i = 0 To $iItems - 1
		; For $j = 0 To $iSubitems - 1
			; $aReturn[$i][$j] = ControlListView($hWin, '', $hListView, 'GetText', $i, $j)
		; Next
	; Next
	For $j = 0 To $iSubitems - 1
		For $i = 0 To $iItems - 1
			$aReturn[$i][$j] = ControlListView($hWin, '', $hListView, 'GetText', $i, $j)
		Next
	Next
	Return SetError(0, _WinAPI_MakeLong($iItems, $iSubitems), $aReturn)
EndFunc   ;==>_GUICtrlListView_GetAllTextToArray
Edited by AZJIO
garbb and JohnOne like this

Share this post


Link to post
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
Sign in to follow this  
Followers 0