LarsJ Posted April 19, 2021 Share Posted April 19, 2021 (edited) I haven't reviewed the current ArrayDisplay code. I don't think that automatic sizing of columns works in a virtual listview. Automatic sizing of columns is based on the column widths being calculated when item/subitem texts are inserted into listview structures. But in a virtual listview, the texts aren't inserted into any structures. Therefore, the column widths cannot be calculated. Of course, all code based on item/subitem texts being stored in listview structures doesn't work immediately in a virtual listview. Depending on how much you want to make out of it, you can perform many of the calculations yourself directly on the basis of the data source. Since these calculations may be time consuming, they must be performed before the ArrayDisplay function is called. Also note that the code in the post at top of the previous page are simple examples, which was what I could find time for on the last day of the Easter holiday. Edited April 19, 2021 by LarsJ pixelsearch and FrancescoDiMuro 2 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
jpm Posted April 20, 2021 Share Posted April 20, 2021 @pixelsearch I don't think I will change the default column size as the code try to fit the length of the data or of the header. I agree that using array range the propose sizing does not follow this rule I don't want to make an extra code for array range that will certainly invove Font calculation. You did not report on perf overall regarding the non virtual listview. Did you find some drawback? Cheers Link to comment Share on other sites More sharing options...
Nine Posted April 20, 2021 Share Posted April 20, 2021 Just an idea. Transform $iMax_Colwidth into a variant where user can define each column size with "|" separator in between. If user provide single number, it stays as it is now. If user provide a string delimited with "|" then use the individual values apply for each column. “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
pixelsearch Posted April 20, 2021 Author Share Posted April 20, 2021 (edited) 6 hours ago, jpm said: You did not report on perf overall regarding the non virtual listview. Did you find some drawback? No drawback at all, on the contrary (even on my antique computer) I tested with 10000, 20000 and 30000 rows (6 cols) array always shuffled. * Virtual view always displays at the speed of sound (after the index is sorted) so there's nothing to compare with a regular view, concerning the moment LV is displayed the 1st time. * Concerning the sorting time : I tested with 3 scripts : - original beta 3.3.15.3 (regular LV) - my reworked script (regular LV speeded) - your actual script (virtual LV) We already tested (thanks Nine) that my reworked script sorts 3 times faster than the original beta 3.3.15.3 Additional tests this morning show that your actual script (virtual LV) sorts between 2 or 3 times faster than my reworked script (2 times faster when array got 10000 rows, 3 times faster when it has 30000 rows) Edit: just re-tested on a 20000 rows LV : your actual script (virtual LV) sorts and displays the results 6 times faster than the original beta 3.3.15.3 (this matches the tests & explanations of preceding lines) Edited April 20, 2021 by pixelsearch Link to comment Share on other sites More sharing options...
jpm Posted April 20, 2021 Share Posted April 20, 2021 Many Thanks for the feedback I will replace your awesome work sorry ... Many Thanks to LarsJ for his suggestion Cheers Link to comment Share on other sites More sharing options...
pixelsearch Posted April 22, 2021 Author Share Posted April 22, 2021 (edited) Hi Jpm I notice you implemented the Array range & transpose in your Virtual listview code, bravo. Also I read this in your script : Case $idListView ; sort If $sArrayRange Then ContinueLoop ; no sorting when Array range selected After several tries, I was able to sort a virtual listview even when it got an Array row range. Here is a functional script : expandcollapse popupOpt( "MustDeclareVars", 1 ) #include <GuiListView.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include "RandomArray.au3" ; LarsJ #include "IndexSort.au3" ; ditto Global $iRows = 10000, $iCols = 6, $aArray, $aIndex, $aIndexes[$iCols], $iSortDir Global $hListView, $aCols = [ "Strings", "Integers", "Floats", "Dates", "Times", "R/C" ], $aWidths = [ 230, 60, 120, 70, 60, 60 ] ;==================== ; Comment / Uncomment 1 of these 2 lines for No row range / row range ;~ Global $iItem_Start = 0, $iItem_End = $iRows - 1 ; No row range Global $iItem_Start = 500, $iItem_End = 599 ; row range ;==================== Global $iRows2 = $iItem_End - $iItem_Start + 1 ; line not to be modified Example() Func Example() ; Check range Local $sMsg = "" Select Case $iItem_Start > $iItem_End ; "minor" fatal error $sMsg = "$iItem_Start > $iItem_End" Case $iRows2 > $iRows ; "serious" fatal error (Autoit3.exe keeps running in the background) $sMsg = "$iRows2 > $iRows" Case $iItem_End >= $iRows ; "serious" fatal error $sMsg = "$iItem_End >= $iRows" Case $iItem_Start < 0 ; ; "serious" fatal error $sMsg = "$iItem_Start < 0" EndSelect If $sMsg Then Exit MsgBox($MB_TOPMOST, $sMsg, "Please fix variables") ; Generate Array & Indexes _Generate_All($aArray, $aIndex, $aIndexes) ; Create GUI Local $hGui = GUICreate( "Virtual ListView + Sort when Array range (2a)", 630+20, 788+30+20 ) ; WinSetOnTop ( $hGui, "", 1 ) ; 1 = $WINDOWS_ONTOP , 0 = $WINDOWS_NOONTOP ; Create ListView Local $idListView = GUICtrlCreateListView( "", 10, 40, 630, 788, $LVS_OWNERDATA, $WS_EX_CLIENTEDGE ) _GUICtrlListView_SetExtendedListViewStyle( $idListView, $LVS_EX_DOUBLEBUFFER + $LVS_EX_FULLROWSELECT ) $hListView = GUICtrlGetHandle( $idListView ) Local $hHeader = _GUICtrlListView_GetHeader( $idListView ) For $i = 0 To $iCols - 1 _GUICtrlListView_AddColumn( $idListView, $aCols[$i], $aWidths[$i] ) Next ; Sorting information $iSortDir = $HDF_SORTUP Local $iColumn = 5, $iColumnPrev = 5 ; col "R/C" _GUICtrlHeader_SetItemFormat( $hHeader, $iColumn, $HDF_STRING + $iSortDir ) ; Register WM_NOTIFY message handler through subclassing Local $pNotifyHandler = DllCallbackGetPtr( DllCallbackRegister( "NotifyHandler", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr" ) ) DllCall( "comctl32.dll", "bool", "SetWindowSubclass", "hwnd", $hGui, "ptr", $pNotifyHandler, "uint_ptr", 0, "dword_ptr", 0 ) ; $iSubclassId = 0, $pData = 0 ; Set the virtual number of items in a virtual list-view control ; GUICtrlSendMsg( $idListView, $LVM_SETITEMCOUNT, $iRows, 0 ) GUICtrlSendMsg( $idListView, $LVM_SETITEMCOUNT, $iRows2, 0 ) ; Show GUI GUISetState( @SW_SHOW ) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idListView ; when this Case is 1st triggered, $aIndex corresponds to last col ("R/C") $iColumn = GUICtrlGetState( $idListView ) If $iColumn <> $iColumnPrev Then _GUICtrlHeader_SetItemFormat( $hHeader, $iColumnPrev, $HDF_STRING ) ; remove sort arrow from previous column $aIndex = $aIndexes[$iColumn] EndIf $iSortDir = (($iColumn = $iColumnPrev) ? ($iSortDir = $HDF_SORTUP ? $HDF_SORTDOWN : $HDF_SORTUP) : ($HDF_SORTUP)) _GUICtrlHeader_SetItemFormat( $hHeader, $iColumn, $HDF_STRING + $iSortDir ) GUICtrlSendMsg( $idListView, $LVM_SETSELECTEDCOLUMN, $iColumn, 0 ) ; GUICtrlSendMsg( $idListView, $LVM_SETITEMCOUNT, $iRows, 0 ) GUICtrlSendMsg( $idListView, $LVM_SETITEMCOUNT, $iRows2, 0 ) $iColumnPrev = $iColumn EndSwitch WEnd ; Cleanup DllCall( "comctl32.dll", "bool", "RemoveWindowSubclass", "hwnd", $hGui, "ptr", $pNotifyHandler, "uint_ptr", 0 ) ; $iSubclassId = 0 GUIDelete( $hGui ) EndFunc ;======================================================================== Func NotifyHandler( $hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $pData ) If $iMsg = 0x004E Then ; 0x004E = $WM_NOTIFY Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Switch HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Case $hListView Switch DllStructGetData( $tNMHDR, "Code" ) Case $LVN_GETDISPINFOW Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $lParam ) Local Static $tText = DllStructCreate( "wchar[50]" ), $pText = DllStructGetPtr( $tText ) ;~ ; LarsJ 1-liner nearly original line (watch out : $iRows changed to $iRows2 +++) ;~ DllStructSetData( $tText, 1, $aArray[( $iSortDir=$HDF_SORTUP?$aIndex[DllStructGetData($tNMLVDISPINFO,"Item")]:$aIndex[$iRows2-1-DllStructGetData($tNMLVDISPINFO,"Item")] )][DllStructGetData($tNMLVDISPINFO,"SubItem")] ) ; Reorganized preceding 1-liner to study it (watch out : $iRows2 +++) If $iSortDir = 0x0400 Then ; 0x0400 = $HDF_SORTUP DllStructSetData($tText, 1, $aArray[$aIndex[$tNMLVDISPINFO.Item]][$tNMLVDISPINFO.SubItem]) Else DllStructSetData($tText, 1, $aArray[$aIndex[$iRows2 -1 -$tNMLVDISPINFO.Item]][$tNMLVDISPINFO.SubItem]) EndIf DllStructSetData( $tNMLVDISPINFO, "Text", $pText ) Return EndSwitch EndSwitch EndIf Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0] #forceref $iSubclassId, $pData EndFunc ;======================================================================== Func _Generate_All(ByRef $aArray, ByRef $aIndex, Byref $aIndexes) ; Generate array ConsoleWrite( "$iRows = " & $iRows & " $iRows2 = " & $iRows2 & @CRLF ) Local $hTimer = TimerInit() $aArray = FAS_Random2DArrayAu3( $iRows, "sifdtr", "abcdefghijklmnopqrstuvwxyz" ) ConsoleWrite( "Generating array = " & TimerDiff( $hTimer ) & @CRLF & @CRLF) ;~ _ArrayDisplay($aArray, "Initial $aArray") ; Sort string column (0) ; --------------------- ;~ Dim $aIndex[$iRows] Dim $aIndex[$iRows2] Local $aCompare = [ 0, 1 ] ConsoleWrite( "Sorting array by column " & 0 & " (string)" & @CRLF ) $hTimer = TimerInit() Local $tIndex = FAS_Sort2DArrayAu3( $aArray, $aCompare ) ;~ For $i = 0 To $iRows - 1 ;~ $aIndex[$i] = DllStructGetData( $tIndex, 1, $i+1 ) ;~ Next Local $k = - 1, $iIdx For $i = 0 To $iRows - 1 $iIdx = DllStructGetData( $tIndex, 1, $i+1 ) If $iIdx >= $iItem_Start And $iIdx <= $iItem_End Then $k += 1 $aIndex[$k] = $iIdx EndIf Next $aIndexes[0] = $aIndex ConsoleWrite( "Sorting array = " & TimerDiff( $hTimer ) & @CRLF ) ;~ _ArrayDisplay($aIndex, "$aIndex (0)") ; Sort number columns ; ------------------- $aCompare[1] = 0 For $i = 1 To $iCols-2 $aCompare[0] = $i ConsoleWrite( "Sorting array by column " & $i & @CRLF ) $hTimer = TimerInit() $tIndex = FAS_Sort2DArrayAu3( $aArray, $aCompare ) ;~ For $j = 0 To $iRows - 1 ;~ $aIndex[$j] = DllStructGetData( $tIndex, 1, $j+1 ) ;~ Next $k = - 1 For $j = 0 To $iRows - 1 $iIdx = DllStructGetData( $tIndex, 1, $j+1 ) If $iIdx >= $iItem_Start And $iIdx <= $iItem_End Then $k += 1 $aIndex[$k] = $iIdx EndIf Next $aIndexes[$i] = $aIndex ConsoleWrite( "Sorting array = " & TimerDiff( $hTimer ) & @CRLF ) ;~ _ArrayDisplay($aIndex, "$aIndex (" & $i & ")") Next ; Sort array by last column ; ------------------------- ConsoleWrite( "Sorting array by column " & $iCols-1 & " (R/C)" & @CRLF ) $hTimer = TimerInit() ;~ For $i = 0 To $iRows - 1 ;~ $aIndex[$i] = $i ;~ Next For $i = $iItem_Start To $iItem_End $aIndex[$i - $iItem_Start] = $i Next $aIndexes[$iCols-1] = $aIndex ConsoleWrite( "Sorting array = " & TimerDiff( $hTimer ) & @CRLF & @CRLF) ;~ _ArrayDisplay($aIndex, "$aIndex (" & $iCols-1 & ")") ;~ _ArrayDisplay($aIndexes, "$aIndexes") EndFunc The preceding code is based on a reworked LarsJ script "ArrayDisplay2.au3" found in this link . Users who wanna try the precedent code will need both include files : https://www.autoitscript.com/forum/applications/core/interface/file/attachment.php?id=67836 #include "RandomArray.au3" ; LarsJ #include "IndexSort.au3" ; ditto In case someone would like to share ideas (or finds a bug in the precedent code), please indicate it in this thread. Thanks ! Updates 04/22/2021 : added a minimal range error checking, to avoid fatal errors when user indicates a bad range. 04/24/2021 : Version 2a (in GUI title) Edited April 24, 2021 by pixelsearch Link to comment Share on other sites More sharing options...
jpm Posted April 22, 2021 Share Posted April 22, 2021 I don't remember why I had this line. I need to think about Thanks Link to comment Share on other sites More sharing options...
pixelsearch Posted April 22, 2021 Author Share Posted April 22, 2021 (edited) I made an update in my previous script just above (added a minimal range checking. The checking seems much more important when the ListView is Virtual) 1 hour ago, jpm said: I don't remember why I had this line. Probably because actually column indexes don't match the items when there's a range. The following code shows the issue : ArrayDisplay2-new.au3 Example_range1D() Func Example_range1D() Local $sRange = "1:" Local $aArray[10] = [8, 6, 7, 1, 9, 4, 0, 5, 3, 2] __ArrayDisplay_Share__($aArray, "range", $sRange) EndFunc ;==>Example_range1D ArrayDisplayInternals2.au3 Case $idListView ; sort ; If $sArrayRange Then ContinueLoop ; no sorting when Array range selected Row 0 ( value 8 ) shouldn't appear when Col 0 is clicked for sorting, but it will appear. Same issue would be found if the Array was 2D and ran with Example(), then a click on any of 5 headers (String, Integers, Floats, Dates, Times) would wrongly display Row 0 ( 9 times out of 10 ) ArrayDisplay2-new.au3 Example() Func Example() Local $iRows = 10 Local $sRange = "1:" ... Edited April 22, 2021 by pixelsearch Link to comment Share on other sites More sharing options...
pixelsearch Posted April 23, 2021 Author Share Posted April 23, 2021 (edited) @jpm & @LarsJ : I would like to modify a sort function found in Jpm's script (based on LarsJ's script) but I don't know how exactly to do it (tests weren't successful). Could you please help ? The goal is, when a row range is selected by the user. to avoid creating structures having the same number of elements as the original array number of rows. Creating indexes could then be more faster. Here is how I solved successfully the creating of filtered indexes in my script above : * Original array : 10.000 rows ($iRows) * Selected range : 100 rows ($iRows2, from row $iItem_Start = 500 To $iItem_End = 599) * Create all indexes using structures (DllStructCreate) by calling FAS_Sort2DArrayAu3() * As there are 10.000 elements in the structure, I did not create the final filtered index like this : ;~ For $i = 0 To $iRows - 1 ; 10000 times ;~ $aIndex[$i] = DllStructGetData( $tIndex, 1, $i+1 ) ;~ Next * Instead, I created a filtered index of 100 elements like that : Local $k = - 1, $iIdx For $i = 0 To $iRows - 1 ; 10000 times $iIdx = DllStructGetData( $tIndex, 1, $i+1 ) If $iIdx >= $iItem_Start And $iIdx <= $iItem_End Then $k += 1 $aIndex[$k] = $iIdx EndIf Next * Though it works very fine, I would like the script to be even more performant and be able to create range structures having only 100 elements each (1st time gain +++) then I could create each final filtered index like that (2nd time gain) : For $i = 0 To $iRows2 - 1 ; 100 times $aIndex[$i] = DllStructGetData( $tIndex, 1, $i+1 ) Next * Let's have a look at Jpm's function __ArrayDisplay_SortArrayStruct() based on LarsJ's function FAS_Sort2DArrayFunc() Func __ArrayDisplay_SortArrayStruct(Const ByRef $aArray, $iCol) Local $iRows = UBound($aArray, $UBOUND_ROWS) Local $iDims = UBound($aArray, $UBOUND_DIMENSIONS) Local $tIndex = DllStructCreate("uint[" & $iRows & "]") Local $pIndex = DllStructGetPtr($tIndex) Static $hDll = DllOpen("kernel32.dll") Static $hDllComp = DllOpen("shlwapi.dll") Local $lo, $hi, $mi, $r ; Sorting by one column For $i = 1 To $iRows - 1 $lo = 0 $hi = $i - 1 Do $mi = Int(($lo + $hi) / 2) If $iDims = 1 Then $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', $aArray[$i], 'wstr', $aArray[DllStructGetData($tIndex, 1, $mi + 1)])[0] Else $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', $aArray[$i][$iCol], 'wstr', $aArray[DllStructGetData($tIndex, 1, $mi + 1)][$iCol])[0] EndIf Switch $r Case -1 $hi = $mi - 1 Case 1 $lo = $mi + 1 Case 0 ExitLoop EndSwitch Until $lo > $hi DllCall($hDll, "none", "RtlMoveMemory", "struct*", $pIndex + ($mi + 1) * 4, "struct*", $pIndex + $mi * 4, "ulong_ptr", ($i - $mi) * 4) DllStructSetData($tIndex, 1, $i, $mi + 1 + ($lo = $mi + 1)) Next Return $tIndex EndFunc ;==>__ArrayDisplay_SortArrayStruct Some lines of the function could be changed like this : ; Local $tIndex = DllStructCreate("uint[" & $iRows & "]") ; 10000 elements Local $tIndex = DllStructCreate("uint[" & $iRows2 & "]") ; 100 elements ; For $i = 1 To $iRows - 1 ; 10000 - 1 times For $i = $iItem_Start + 1 To $iItem_End ; 100 - 1 times But what about those terrible variables in the function ($lo, $hi, especially $mi), the 'RtlMoveMemory' message (it includes $i) etc... How should this be scripted no matter the user selects a row range or not ? The 2 optional parameters could be $iItem_Start and $iItem_End, knowing that $iRows2 = $iItem_End - $iItem_Start + 1 (though in my script all these 3 variables are declared Global) If you guys think it's worth a try, thanks for sharing your solution Edited April 23, 2021 by pixelsearch Link to comment Share on other sites More sharing options...
LarsJ Posted April 23, 2021 Share Posted April 23, 2021 You can use an aRange index as shown here. Not tested. If this code is to work when there is no range and all rows are included, you must use an aRange index that includes all rows. But it'll be more performance optimal to use two sets of code with and without row ranges. The aRange index must of course be added to many different places in the code. expandcollapse popupLocal $iItem_Start = 500, $iItem_End = 599, $iRange = $iItem_End - $iItem_Start + 1, $aRange[$iRange] For $i = 0 To $iRange - 1 $aRange[$i] = $iItem_Start + $i Next Func __ArrayDisplay_SortArrayStruct(Const ByRef $aArray, $iCol) ;Local $iRows = UBound($aArray, $UBOUND_ROWS) Local $iDims = UBound($aArray, $UBOUND_DIMENSIONS) Local $tIndex = DllStructCreate("uint[" & $iRange & "]") Local $pIndex = DllStructGetPtr($tIndex) Local Static $hDll = DllOpen("kernel32.dll") Local Static $hDllComp = DllOpen("shlwapi.dll") Local $lo, $hi, $mi, $r ; Sorting by one column For $i = 1 To $iRange - 1 $lo = 0 $hi = $i - 1 Do $mi = Int(($lo + $hi) / 2) If $iDims = 1 Then $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', $aArray[$aRange[$i]], 'wstr', $aArray[$aRange[DllStructGetData($tIndex, 1, $mi + 1)]])[0] Else $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', $aArray[$aRange[$i]][$iCol], 'wstr', $aArray[$aRange[DllStructGetData($tIndex, 1, $mi + 1)]][$iCol])[0] EndIf Switch $r Case -1 $hi = $mi - 1 Case 1 $lo = $mi + 1 Case 0 ExitLoop EndSwitch Until $lo > $hi DllCall($hDll, "none", "RtlMoveMemory", "struct*", $pIndex + ($mi + 1) * 4, "struct*", $pIndex + $mi * 4, "ulong_ptr", ($i - $mi) * 4) DllStructSetData($tIndex, 1, $i, $mi + 1 + ($lo = $mi + 1)) Next Return $tIndex EndFunc ;==>__ArrayDisplay_SortArrayStruct pixelsearch 1 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
pixelsearch Posted April 23, 2021 Author Share Posted April 23, 2021 (edited) Many thanks LarsJ, I'll test your code asap (as soon as my back pain allows me to) and report here. 5 hours ago, LarsJ said: Not tested. Just tested and It works fine, bravo Edited April 23, 2021 by pixelsearch Link to comment Share on other sites More sharing options...
pixelsearch Posted April 23, 2021 Author Share Posted April 23, 2021 (edited) @LarsJ your function was challenging. It helped me this evening to achieve my initial goal... and it worked Here is a script without any aRange index and using "For $iItem = $iItem_Start + 1 To $iItem_End" in Func __ArrayDisplay_SortArrayStruct() . It works with or without range and there should be no noticeable performance penalty : expandcollapse popupOpt( "MustDeclareVars", 1 ) #include <GuiListView.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include "RandomArray.au3" ; LarsJ Global $iRows = 10000, $iCols = 6, $aArray, $aIndex, $aIndexes[$iCols], $iSortDir Global $hListView, $aCols = [ "Strings", "Integers", "Floats", "Dates", "Times", "R/C" ], $aWidths = [ 230, 60, 120, 70, 60, 60 ] ;==================== ; Comment / Uncomment 1 of these 2 lines for No row range / row range ;~ Global $iItem_Start = 0, $iItem_End = $iRows - 1 ; No row range Global $iItem_Start = 500, $iItem_End = 599 ; row range ;==================== Global $iRange = $iItem_End - $iItem_Start + 1 ; line not to be modified Example() Func Example() ; Check range Local $sMsg = "" Select Case $iItem_Start < 0 $sMsg = "$iItem_Start < 0" Case $iItem_End >= $iRows $sMsg = "$iItem_End >= $iRows" Case $iItem_Start > $iItem_End $sMsg = "$iItem_Start > $iItem_End" EndSelect If $sMsg Then Exit MsgBox($MB_TOPMOST, $sMsg, "Please fix variables") ; Generate Array & Indexes _Generate_All($aArray, $aIndex, $aIndexes) ; Create GUI Local $hGui = GUICreate( "Virtual ListView + Sort when Array range (2b)", 630+20, 788+30+20 ) ; Create ListView Local $idListView = GUICtrlCreateListView( "", 10, 40, 630, 788, $LVS_OWNERDATA, $WS_EX_CLIENTEDGE ) _GUICtrlListView_SetExtendedListViewStyle( $idListView, $LVS_EX_DOUBLEBUFFER + $LVS_EX_FULLROWSELECT ) $hListView = GUICtrlGetHandle( $idListView ) Local $hHeader = _GUICtrlListView_GetHeader( $idListView ) For $i = 0 To $iCols - 1 _GUICtrlListView_AddColumn( $idListView, $aCols[$i], $aWidths[$i] ) Next ; Sorting information $iSortDir = $HDF_SORTUP Local $iColumn = 5, $iColumnPrev = 5 ; col "R/C" _GUICtrlHeader_SetItemFormat( $hHeader, $iColumn, $HDF_STRING + $iSortDir ) ; Register WM_NOTIFY message handler through subclassing Local $pNotifyHandler = DllCallbackGetPtr( DllCallbackRegister( "NotifyHandler", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr" ) ) DllCall( "comctl32.dll", "bool", "SetWindowSubclass", "hwnd", $hGui, "ptr", $pNotifyHandler, "uint_ptr", 0, "dword_ptr", 0 ) ; $iSubclassId = 0, $pData = 0 ; Set the virtual number of items in a virtual list-view control GUICtrlSendMsg( $idListView, $LVM_SETITEMCOUNT, $iRange, 0 ) ; Show GUI GUISetState( @SW_SHOW ) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idListView ; sort $iColumn = GUICtrlGetState( $idListView ) If $iColumn <> $iColumnPrev Then _GUICtrlHeader_SetItemFormat( $hHeader, $iColumnPrev, $HDF_STRING ) $aIndex = $aIndexes[$iColumn] EndIf $iSortDir = (($iColumn = $iColumnPrev) ? ($iSortDir = $HDF_SORTUP ? $HDF_SORTDOWN : $HDF_SORTUP) : ($HDF_SORTUP)) _GUICtrlHeader_SetItemFormat( $hHeader, $iColumn, $HDF_STRING + $iSortDir ) GUICtrlSendMsg( $idListView, $LVM_SETSELECTEDCOLUMN, $iColumn, 0 ) GUICtrlSendMsg( $idListView, $LVM_SETITEMCOUNT, $iRange, 0 ) $iColumnPrev = $iColumn EndSwitch WEnd ; Cleanup DllCall( "comctl32.dll", "bool", "RemoveWindowSubclass", "hwnd", $hGui, "ptr", $pNotifyHandler, "uint_ptr", 0 ) ; $iSubclassId = 0 GUIDelete( $hGui ) EndFunc ;======================================================================== Func NotifyHandler( $hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $pData ) If $iMsg = 0x004E Then ; 0x004E = $WM_NOTIFY Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Switch HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Case $hListView Switch DllStructGetData( $tNMHDR, "Code" ) Case $LVN_GETDISPINFOW Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $lParam ) Local Static $tText = DllStructCreate( "wchar[50]" ), $pText = DllStructGetPtr( $tText ) ;~ ; LarsJ 1-liner nearly original line (watch out : $iRows changed to $iRange +++) ;~ DllStructSetData( $tText, 1, $aArray[( $iSortDir=$HDF_SORTUP?$aIndex[DllStructGetData($tNMLVDISPINFO,"Item")]:$aIndex[$iRange-1-DllStructGetData($tNMLVDISPINFO,"Item")] )][DllStructGetData($tNMLVDISPINFO,"SubItem")] ) ; Reorganized preceding 1-liner to study it If $iSortDir = 0x0400 Then ; 0x0400 = $HDF_SORTUP DllStructSetData($tText, 1, $aArray[$aIndex[$tNMLVDISPINFO.Item]][$tNMLVDISPINFO.SubItem]) Else DllStructSetData($tText, 1, $aArray[$aIndex[$iRange -1 -$tNMLVDISPINFO.Item]][$tNMLVDISPINFO.SubItem]) EndIf DllStructSetData( $tNMLVDISPINFO, "Text", $pText ) Return EndSwitch EndSwitch EndIf Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0] #forceref $iSubclassId, $pData EndFunc ;======================================================================== Func _Generate_All(ByRef $aArray, ByRef $aIndex, Byref $aIndexes) ; Generate array ConsoleWrite( "$iRows = " & $iRows & " $iRange = " & $iRange & @CRLF ) Local $hTimer = TimerInit() $aArray = FAS_Random2DArrayAu3( $iRows, "sifdtr", "abcdefghijklmnopqrstuvwxyz" ) ConsoleWrite( "Generating array = " & TimerDiff( $hTimer ) & @CRLF & @CRLF) ;~ _ArrayDisplay($aArray, "Initial $aArray") ; Prepare indexes for all columns (except last column "R/C") ; --------------------------------------------------------- Dim $aIndex[$iRange] Local $tIndex For $iCol = 0 To $iCols - 2 ConsoleWrite( "Sorting array by column " & $iCol & @CRLF ) $hTimer = TimerInit() $tIndex = __ArrayDisplay_SortArrayStruct( $aArray, $iCol ) For $i = 0 To $iRange - 1 $aIndex[$i] = DllStructGetData( $tIndex, 1, $i+1 ) + $iItem_Start Next $aIndexes[$iCol] = $aIndex ConsoleWrite( "Sorting array = " & TimerDiff( $hTimer ) & @CRLF ) ;~ _ArrayDisplay($aIndex, "$aIndex (" & $iCol & ")") Next ; Sort array by last column ; ------------------------- ConsoleWrite( "Sorting array by column " & $iCols-1 & " (R/C)" & @CRLF ) $hTimer = TimerInit() For $i = $iItem_Start To $iItem_End $aIndex[$i - $iItem_Start] = $i Next $aIndexes[$iCols-1] = $aIndex ConsoleWrite( "Sorting array = " & TimerDiff( $hTimer ) & @CRLF & @CRLF) ;~ _ArrayDisplay($aIndex, "$aIndex (" & $iCols-1 & ")") ;~ _ArrayDisplay($aIndexes, "$aIndexes") EndFunc ;======================================================================== Func __ArrayDisplay_SortArrayStruct(Const ByRef $aArray, $iCol) ; $iItem_Start & $iItem_End & $iRange are Global variables in this script Local $iDims = UBound($aArray, $UBOUND_DIMENSIONS) Local $tIndex = DllStructCreate("uint[" & $iRange & "]") Local $pIndex = DllStructGetPtr($tIndex) Static $hDll = DllOpen("kernel32.dll") Static $hDllComp = DllOpen("shlwapi.dll") Local $lo, $hi, $mi, $r, $i = 0 ; Sorting by one column For $iItem = $iItem_Start + 1 To $iItem_End $i += 1 $lo = 0 $hi = $i - 1 Do $mi = Int(($lo + $hi) / 2) If $iDims = 1 Then $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', $aArray[$iItem], 'wstr', $aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iItem_Start])[0] Else $r = DllCall($hDllComp, 'int', 'StrCmpLogicalW', 'wstr', $aArray[$iItem][$iCol], 'wstr', $aArray[DllStructGetData($tIndex, 1, $mi + 1) + $iItem_Start][$iCol])[0] EndIf Switch $r Case -1 $hi = $mi - 1 Case 1 $lo = $mi + 1 Case 0 ExitLoop EndSwitch Until $lo > $hi DllCall($hDll, "none", "RtlMoveMemory", "struct*", $pIndex + ($mi + 1) * 4, "struct*", $pIndex + $mi * 4, "ulong_ptr", ($i - $mi) * 4) DllStructSetData($tIndex, 1, $i, $mi + 1 + ($lo = $mi + 1)) Next Return $tIndex EndFunc ;==>__ArrayDisplay_SortArrayStruct Update 04/24/2021 * Call __ArrayDisplay_SortArrayStruct() with 2 Params only, as $iItem_Start & $iItem_End & $iRange are Global variables in this script. * Simplified array range checking * Version 2b (in GUI title) Edited April 24, 2021 by pixelsearch Link to comment Share on other sites More sharing options...
pixelsearch Posted April 24, 2021 Author Share Posted April 24, 2021 (edited) @jpm good news concerning ArrayDisplayInternals2.au3 . I found a way to totally get rid of Case -7 ; $NM_SETFOCUS and place all its code in a separate function (badly) named _Focus . This will reduce the code in the subclassing function, also $_g_ArrayDisplay_bFirstFocus isn't needed anymore. This is a part of what stays in Main code (some lines have been moved and placed just after the subclassing is triggered) expandcollapse popup... ; Register WM_NOTIFY message handler through subclassing Local $p__ArrayDisplay_NotifyHandler = DllCallbackGetPtr(DllCallbackRegister("__ArrayDisplay_NotifyHandler", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr")) DllCall("comctl32.dll", "bool", "SetWindowSubclass", "hwnd", $_g_ArrayDisplay_hGUI, "ptr", $p__ArrayDisplay_NotifyHandler, "uint_ptr", 0, "dword_ptr", 0) ; $iSubclassId = 0, $pData = 0 Local $iColFill = $_g_ArrayDisplay_nCols + $_g_ArrayDisplay_iDisplayRow ; Align columns if required - $iColAlign = 2 for Right and 4 for Center If $iColAlign Then ; Loop through columns For $i = 0 To $iColFill - 1 __ArrayDisplay_JustifyColumn($idListView, $i, $iColAlign / 2) Next EndIf GUICtrlSendMsg($idListView, (0x1000 + 47), $iItemCount, 0) ; $LVM_SETITEMCOUNT (test : has to be placed b4 "Get Row Height" as Jpm did) ; Get row height Local $tRECT = DllStructCreate("struct; long Left;long Top;long Right;long Bottom; endstruct") ; $tagRECT DllCall("user32.dll", "struct*", "SendMessageW", "hwnd", $_g_ArrayDisplay_hListView, "uint", $_ARRAYCONSTANT_LVM_GETITEMRECT, "wparam", 0, "struct*", $tRECT) ; Set required GUI height Local $aiWin_Pos = WinGetPos($_g_ArrayDisplay_hGUI) Local $aiLV_Pos = ControlGetPos($_g_ArrayDisplay_hGUI, "", $idListView) $iHeight = (($iItemCount + 3) * (DllStructGetData($tRECT, "Bottom") - DllStructGetData($tRECT, "Top"))) + $aiWin_Pos[3] - $aiLV_Pos[3] ; Check min/max height If $iHeight > @DesktopHeight - 100 Then $iHeight = @DesktopHeight - 100 ElseIf $iHeight < $iMinSize Then $iHeight = $iMinSize EndIf Local $iWidth = _Focus() ; <=========== ; Display and resize dialog GUISetState(@SW_HIDE, $_g_ArrayDisplay_hGUI) WinMove($_g_ArrayDisplay_hGUI, "", (@DesktopWidth - $iWidth) / 2, (@DesktopHeight - $iHeight) / 2, $iWidth, $iHeight) GUISetState(@SW_SHOW, $_g_ArrayDisplay_hGUI) ... _Focus function : expandcollapse popupFunc _Focus() Local $bColDisplay = 1 ; Jpm will know better what to do with that variable value ; Adjust dialog width Local $iColFill = $_g_ArrayDisplay_iSubItem_End + $_g_ArrayDisplay_iDisplayRow Local $iWidth = 40, $iColWidth = 0, $aiColWidth[$iColFill + 1], $iMin_ColWidth = 55 ; Get required column widths to fit items Local $iColWidthHeader For $i = 0 To $iColFill GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 30), $i, -1) ; $LVM_SETCOLUMNWIDTH $LVSCW_AUTOSIZE $iColWidth = GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 29), $i, 0) ; $LVM_GETCOLUMNWIDTH If $iColWidth = 0 Then ExitLoop GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 30), $i, -2) ; $LVM_SETCOLUMNWIDTH $LVSCW_AUTOSIZE_USEHEADER $iColWidthHeader = GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 29), $i, 0) ; $GETCOLUMNWIDTH ; Set minimum if required If $iColWidth < $iMin_ColWidth And $iColWidthHeader < $iMin_ColWidth Then GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 30), $i, $iMin_ColWidth) ; $LVM_SETCOLUMNWIDTH $iColWidth = $iMin_ColWidth ElseIf $iColWidthHeader < $iColWidth Then GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 30), $i, $iColWidth) ; $LVM_SETCOLUMNWIDTH Else $iColWidth = $iColWidthHeader EndIf If IsInt($bColDisplay) Then ; Add to total width $iWidth += $iColWidth EndIf ; Store value $aiColWidth[$i] = $iColWidth Next ; Now check max size If $iWidth > @DesktopWidth - 100 Then ; Apply max col width limit to reduce width $iWidth = 40 For $i = 0 To $iColFill If True Or $i = 0 Or ($i >= $_g_ArrayDisplay_iSubItem_Start And $i <= $_g_ArrayDisplay_iSubItem_End + 1) Then If $aiColWidth[$i] > $_g_ArrayDisplay_iMax_ColWidth Then ; Reset width GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 30), $i, $_g_ArrayDisplay_iMax_ColWidth) ; $LVM_SETCOLUMNWIDTH $iWidth += $_g_ArrayDisplay_iMax_ColWidth Else ; Retain width $iWidth += $aiColWidth[$i] EndIf ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $iWidth = ' & $iWidth & " $i = " & $i & @CRLF & '>Error code: ' & @error & ' Extended code: ' & @extended & ' (0x' & Hex(@extended) & ')' & @CRLF) ;### Debug Console EndIf Next EndIf Local $aWinPos = WinGetPos($_g_ArrayDisplay_hGUI) ; Check max/min width If $iWidth > @DesktopWidth - 100 Then $iWidth = @DesktopWidth - 100 ElseIf $iWidth > $_g_ArrayDisplay_iMax_ColWidth * $_g_ArrayDisplay_nCols Then $iWidth = $_g_ArrayDisplay_iMax_ColWidth * $_g_ArrayDisplay_nCols EndIf ; Allow for borders with vertical scrollbar If $aWinPos[3] = (@DesktopHeight - 100) Then $iWidth += 15 ; not needed anymore ; WinMove($_g_ArrayDisplay_hGUI, "", (@DesktopWidth - $iWidth) / 2, $aWinPos[1], $iWidth, $aWinPos[3]) Return $iWidth EndFunc I'm pretty sure that most of the "Main" code above could be transferred from Main into _Focus() using the correct parameters. Of course, it seems also that all the content of _Focus() could be placed back in Main, but imho it seems more pleasant to have it all in a separate function, you'll decide. Anyway, display is correct on my computer with the code above (columns size, GUI width & height etc...) Edited April 24, 2021 by pixelsearch Link to comment Share on other sites More sharing options...
jpm Posted April 25, 2021 Share Posted April 25, 2021 I already did the same. Now I face the transpose with arrayrange which imply to sort the whole as the indexes are relative to the complete array. Perhaps I will do as for the transpose a local subset array Thanks for the help Link to comment Share on other sites More sharing options...
pixelsearch Posted April 25, 2021 Author Share Posted April 25, 2021 (edited) Hey Jpm, we're here nearly at same time Glad you already did same. As I prepared some update a few minutes ago, I'll post it anyway, just as it was prepared : Update 04/25/2021 "Forget the code just above. 2 separate functions make it clearer : 1 for calculating GUI Width, 1 for calculating GUI Height as shown below" expandcollapse popup... ; Create GUI ; no need of $iOrgWidth, changed it to $iWidth in both lines : Local $iWidth = 210, $iHeight = 200, $iMinSize = 250 $_g_ArrayDisplay_hGUI = GUICreate($sTitle, $iWidth, $iHeight, Default, Default, BitOR($_ARRAYCONSTANT_WS_SIZEBOX, $_ARRAYCONSTANT_WS_MINIMIZEBOX, $_ARRAYCONSTANT_WS_MAXIMIZEBOX)) ... ;~ Local Const $_ARRAYCONSTANT_LVM_GETITEMRECT = (0x1000 + 14) ... ; Register WM_NOTIFY message handler through subclassing Local $p__ArrayDisplay_NotifyHandler = DllCallbackGetPtr(DllCallbackRegister("__ArrayDisplay_NotifyHandler", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr")) DllCall("comctl32.dll", "bool", "SetWindowSubclass", "hwnd", $_g_ArrayDisplay_hGUI, "ptr", $p__ArrayDisplay_NotifyHandler, "uint_ptr", 0, "dword_ptr", 0) ; $iSubclassId = 0, $pData = 0 GUICtrlSendMsg($idListView, (0x1000 + 47), $iItemCount, 0) ; $LVM_SETITEMCOUNT $iWidth = __ArrayDisplay_GuiWidth() ; <========== $iHeight = __ArrayDisplay_GuiHeight($idListView, $iItemCount, $iMinSize) ; <========== If $iVerbose Then SplashOff() #EndRegion GUI generation ; Display and resize dialog GUISetState(@SW_HIDE, $_g_ArrayDisplay_hGUI) WinMove($_g_ArrayDisplay_hGUI, "", (@DesktopWidth - $iWidth) / 2, (@DesktopHeight - $iHeight) / 2, $iWidth, $iHeight) GUISetState(@SW_SHOW, $_g_ArrayDisplay_hGUI) ... ;================================================================ Func __ArrayDisplay_GuiWidth() Local $bColDisplay = 1 ; Jpm will know better what to do with that variable value ; Adjust dialog width Local $iColFill = $_g_ArrayDisplay_iSubItem_End + $_g_ArrayDisplay_iDisplayRow Local $iWidth = 40, $iColWidth = 0, $aiColWidth[$iColFill + 1], $iMin_ColWidth = 55 ; Get required column widths to fit items Local $iColWidthHeader For $i = 0 To $iColFill GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 30), $i, -1) ; $LVM_SETCOLUMNWIDTH $LVSCW_AUTOSIZE $iColWidth = GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 29), $i, 0) ; $LVM_GETCOLUMNWIDTH If $iColWidth = 0 Then ExitLoop GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 30), $i, -2) ; $LVM_SETCOLUMNWIDTH $LVSCW_AUTOSIZE_USEHEADER $iColWidthHeader = GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 29), $i, 0) ; $GETCOLUMNWIDTH ; Set minimum if required If $iColWidth < $iMin_ColWidth And $iColWidthHeader < $iMin_ColWidth Then GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 30), $i, $iMin_ColWidth) ; $LVM_SETCOLUMNWIDTH $iColWidth = $iMin_ColWidth ElseIf $iColWidthHeader < $iColWidth Then GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 30), $i, $iColWidth) ; $LVM_SETCOLUMNWIDTH Else $iColWidth = $iColWidthHeader EndIf If IsInt($bColDisplay) Then ; Add to total width $iWidth += $iColWidth EndIf ; Store value $aiColWidth[$i] = $iColWidth Next ; Now check max size If $iWidth > @DesktopWidth - 100 Then ; Apply max col width limit to reduce width $iWidth = 40 For $i = 0 To $iColFill If True Or $i = 0 Or ($i >= $_g_ArrayDisplay_iSubItem_Start And $i <= $_g_ArrayDisplay_iSubItem_End + 1) Then If $aiColWidth[$i] > $_g_ArrayDisplay_iMax_ColWidth Then ; Reset width GUICtrlSendMsg($_g_ArrayDisplay_idListView, (0x1000 + 30), $i, $_g_ArrayDisplay_iMax_ColWidth) ; $LVM_SETCOLUMNWIDTH $iWidth += $_g_ArrayDisplay_iMax_ColWidth Else ; Retain width $iWidth += $aiColWidth[$i] EndIf ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $iWidth = ' & $iWidth & " $i = " & $i & @CRLF & '>Error code: ' & @error & ' Extended code: ' & @extended & ' (0x' & Hex(@extended) & ')' & @CRLF) ;### Debug Console EndIf Next EndIf Local $aWinPos = WinGetPos($_g_ArrayDisplay_hGUI) ; Check max/min width If $iWidth > @DesktopWidth - 100 Then $iWidth = @DesktopWidth - 100 ElseIf $iWidth > $_g_ArrayDisplay_iMax_ColWidth * $_g_ArrayDisplay_nCols Then $iWidth = $_g_ArrayDisplay_iMax_ColWidth * $_g_ArrayDisplay_nCols EndIf ; Allow for borders with vertical scrollbar If $aWinPos[3] = (@DesktopHeight - 100) Then $iWidth += 15 ; not needed anymore ; WinMove($_g_ArrayDisplay_hGUI, "", (@DesktopWidth - $iWidth) / 2, $aWinPos[1], $iWidth, $aWinPos[3]) Return $iWidth EndFunc ;==>__ArrayDisplay_GuiWidth() ;================================================================ Func __ArrayDisplay_GuiHeight($idListView, $iItemCount, $iMinSize) ; Get row height Local $tRECT = DllStructCreate("struct; long Left;long Top;long Right;long Bottom; endstruct") ; $tagRECT DllCall("user32.dll", "struct*", "SendMessageW", "hwnd", $_g_ArrayDisplay_hListView, "uint", (0x1000 + 14), "wparam", 0, "struct*", $tRECT) ; $LVM_GETITEMRECT ; Set required GUI height Local $aiWin_Pos = WinGetPos($_g_ArrayDisplay_hGUI) Local $aiLV_Pos = ControlGetPos($_g_ArrayDisplay_hGUI, "", $idListView) Local $iHeight = (($iItemCount + 3) * (DllStructGetData($tRECT, "Bottom") - DllStructGetData($tRECT, "Top"))) + $aiWin_Pos[3] - $aiLV_Pos[3] ; Check min/max height If $iHeight > @DesktopHeight - 100 Then $iHeight = @DesktopHeight - 100 ElseIf $iHeight < $iMinSize Then $iHeight = $iMinSize EndIf Return $iHeight EndFunc ;==>__ArrayDisplay_GuiHeight() All portions of code not indicated after subclassing is ON are still placed just before it, for example : ; Align columns if required - $iColAlign = 2 for Right and 4 for Center (b4 subclassing is ok) (code) ; Sorting information (b4 subclassing is ok) (code) I'll try to study a bit the transpose part (though I never transposed anything until now !) Edited April 25, 2021 by pixelsearch Link to comment Share on other sites More sharing options...
pixelsearch Posted April 25, 2021 Author Share Posted April 25, 2021 (edited) 8 hours ago, jpm said: Now I face the transpose with arrayrange which imply to sort the whole as the indexes are relative to the complete array. Perhaps I will do as for the transpose a local subset array Well... as you already scripted it for a full transpose with your function __ArrayDisplay_Transpose, then it seems coherent to do same when the transpose includes an array range (there will be less elements in the subset array) On 4/9/2021 at 6:44 AM, jpm said: I think that I will reject the transpose when number of rows if more than 100 or LESS as to visualize the info it is needed to use still a lot of horizontal shift perhaps 100 is a litle small but what can be a better value? I read this in an interesting LarsJ's link : On 10/12/2019 at 7:23 AM, LarsJ said: If the number of columns is limited to a few hundred, the built-in listview header can support the columns[...] TooManyCols.au3 shows what happens if the listview contains more columns than the built-in header is able to support. Drag the thumb in the horizontal scrollbar all the way to the right to see that the header items are simply missing. A test I just made indicates that the rectangle of all built-in ListView headers shouldn't be wider than 32767 pixels, this is about 327 cols x 100 pixels each (column width). If there are additional columns then headers will be missing (unless I guess the listview got the LVS_OWNERDRAWFIXED style but that's not our case). It's not the number of columns that indicates if a header will appear or not, but it's the total of columns width (in pixels) that has to be <= 32767 So when using virtual listviews, it seems difficult to know in advance if you should allow the user to transpose (with or without array range) as you don't know how many initial rows will have headers after they become columns (in case there are a few hundred initials rows... or much more as we're talking about virtual listviews) Another point to think of : it shouldn't be a problem to display 300 cols of 100 pixels each, but what about the final number of rows (the ex-columns) ? If there are only a few final rows, then it's ok, but if there are a few hundreds... Now good luck with all these calculations before accepting to transpose or not. Edit: here is a pic with 327 cols of 100 pixels each => 32700 pixels (i.e. the "row" col + cols from 0 to 325 => 327 cols displaying a full header) The 67 remaining pixels are displayed in a truncated header ("Col 326") Edited April 25, 2021 by pixelsearch Link to comment Share on other sites More sharing options...
jpm Posted April 27, 2021 Share Posted April 27, 2021 (edited) my final touch. I hope ... I don't except to work on too many cols Cheers Edited: see below for correct upload Edited April 28, 2021 by jpm to fix array 1D with range Link to comment Share on other sites More sharing options...
pixelsearch Posted April 27, 2021 Author Share Posted April 27, 2021 (edited) Hi Jpm Great job! If you don't mind, I'll indicate in this post which problems I encounter with your most recent upload. Please feel free to re-upload a new version when the problem is serious, so we always test the most recent version. An example of serious problem with the last upload in preceding post Example_range1D() Func Example_range1D() Local $sRange = "1:" Local $aArray[2] = [0, 1] _DebugArrayDisplay($aArray, "range", $sRange) $g_hArrayDisplay_Share($aArray, "range", $sRange) EndFunc ;==>Example_range1D "ArrayDisplayInternals2.au3" (829) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.: $aTemp[$iRow][$iCol] = $_g_ArrayDisplay_aArray[$i][$j] $aTemp[$iRow][$iCol] = ^ ERROR >Exit code: 1 As the original array is 1D, then $_g_ArrayDisplay_aArray[$i][$j] will generate an error in Func __ArrayDisplay_CreateSubArray() Apologies if I was mistaken. Edit #1 : line 636 Dim $_g_ArrayDisplay_aIndexes[$_g_ArrayDisplay_nCols + 2] ; Shouldn't it be : Dim $_g_ArrayDisplay_aIndexes[$_g_ArrayDisplay_nCols + 1] Edit #2 : some cosmetic changes if you like... line 824 Local $iRow = ($_g_ArrayDisplay_iSortDir = 0x00000400) ? $_g_ArrayDisplay_aIndex[$iItem] : $_g_ArrayDisplay_aIndex[$_g_ArrayDisplay_nRows - 1 - DllStructGetData($tNMLVDISPINFO, "Item")] could be : Local $iRow = ($_g_ArrayDisplay_iSortDir = 0x00000400) ? $_g_ArrayDisplay_aIndex[$iItem] : $_g_ArrayDisplay_aIndex[$_g_ArrayDisplay_nRows - 1 - $iItem] 3 same lines 703 - 711 - 725 : DllStructSetData($tNMLVDISPINFO, "Text", $pText) could be replaced by 1 line only (728) DllStructSetData($tNMLVDISPINFO, "Text", $pText) Return Edited April 28, 2021 by pixelsearch Link to comment Share on other sites More sharing options...
jpm Posted April 28, 2021 Share Posted April 28, 2021 Thanks again Edit "1 is wrong as an extra entry is needed when displaying the row number it should be Dim $_g_ArrayDisplay_aIndexes[$_g_ArrayDisplay_nCols + $_g_ArrayDisplay_iDisplayRow + 1] I fix the 1D support, I should have check it before ... I reupload ArrayDisplayInternals2.7z Link to comment Share on other sites More sharing options...
pixelsearch Posted April 28, 2021 Author Share Posted April 28, 2021 (edited) Hi Jpm, It seems ok now that you fixed it all. I just had an idea. Pics being better than words... When transposing, it allows the user to see in "Row" column the original headers (if any) before transposing so they are not lost anymore. Sorting on the "Row" column keeps working. Changes could be these (dirty code quickly tested) : ; actual If $_g_ArrayDisplay_iTranspose Then DllStructSetData($tText, 1, "Col " & $iRow + $_g_ArrayDisplay_iItem_Start) Else ; becomes If $_g_ArrayDisplay_iTranspose Then Local $sCaptionCplt = "" If $iRow + $_g_ArrayDisplay_iItem_Start < Ubound($asHeader) _ And StringStripWS($asHeader[$iRow + $_g_ArrayDisplay_iItem_Start], 1 + 2) <> "" Then $sCaptionCplt = " (" & StringStripWS($asHeader[$iRow + $_g_ArrayDisplay_iItem_Start], 1 + 2) & ")" EndIf DllStructSetData($tText, 1, "Col " & ($iRow + $_g_ArrayDisplay_iItem_Start) & $sCaptionCplt) Else Though there are several lines of code, this part of the message handler doesn't happen a lot (it requires 3 conditions : "row " column to be displayed + "row" column being actually tested + transpose active. Edited April 28, 2021 by pixelsearch Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now