Popular Post LarsJ Posted March 13, 2021 Popular Post Share Posted March 13, 2021 (edited) OverviewFirst part First part of this example was published March/April 2021 and contains these main sections: Simple implementation of a virtual treeview created from data in a source file Multi-line treeview items and a discussion of an example in the help file Other sections about Item images, Performance tests and Treeview structure Second part Second part of the example has started up in January 2023: Updated all first part examples (item param offset, performance optimizations) Short summary of first part and further development of Real virtual treeviews TreeView posts Other posts and examples regarding treeviews: Saving/reading item levels and texts is the starting point for this example Use of colors and fonts in treeview items through custom draw code Virtual treeviews The basic idea behind implementing both a virtual treeview and a virtual listview is to store as much data as possible in the data source and as little data as possible in the treeview and listview. The purpose is especially to performance optimize creation of the treeview and listview. A virtual listview is created with the LVS_OWNERDATA style. To populate listview items and subitems, you respond to LVN_GETDISPINFO notifications contained in WM_NOTIFY messages. A virtual treeview isn't created based on a particular style of the treeview. A virtual treeview is created by setting LPSTR_TEXTCALLBACK and I_CHILDRENCALLBACK values in the TVITEM structure used to create the treeview items. The LPSTR_TEXTCALLBACK and I_CHILDRENCALLBACK values cause TVN_GETDISPINFO notifications (also contained in WM_NOTIFY messages) to be generated. To populate treeview items and child items, you respond to these TVN_GETDISPINFO notifications. Create treeview from data sourceIn the attempt to implement a virtual treeview, the first step is to create the treeview based on a data source e.g. a simple text file. This post demonstrates how to uniquely store a treeview in a text file and then uniquely restore the same treeview. It's sufficient to store treeview item levels and texts. This is a slightly modified version of TreeView.txt: 0|0 0|1 0|2 1|3 1|This 1|is 2|6 2|a 2|very 2|nice 3|10 3|TreeView 0|, (comma) 1|13 1|indeed. 0|15 And a slightly modified version of the code to recreate the treeview (1) Conventional TreeView.au3) expandcollapse popup#AutoIt3Wrapper_Au3Check_Parameters=-d -w- 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=Y Opt( "MustDeclareVars", 1 ) #include <GUIConstants.au3> #include <WindowsConstants.au3> #include <GuiTreeView.au3> Global $hTreeView Example() Func Example() ; Create GUI Local $hGui = GUICreate( "Create Conventional TreeView From File", 400, 300, 600, 300, $GUI_SS_DEFAULT_GUI ) ; Create TreeView Local $idTreeView = GUICtrlCreateTreeView( 4, 4, 392, 292, $GUI_SS_DEFAULT_TREEVIEW, $WS_EX_CLIENTEDGE ) $hTreeView = GUICtrlGetHandle( $idTreeView ) ; Read level and text of TreeView items and create TreeView CreateTreeView( FileReadToArray( "TreeView.txt" ) ) ; Show GUI GUISetState( @SW_SHOW, $hGui ) ; Loop While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd ; Cleanup GUIDelete( $hGui ) EndFunc ; Create conventional TreeView Func CreateTreeView( $aItems ) ; TreeView item information Local $aItem, $hItem ; TreeView level information Local $aLevels[100], $iLevel = 0, $iLevelPrev = 0 ; $aLevels[$iLevel] contains the last item of that level ; Add TreeView root $aItem = StringSplit( $aItems[0], "|", 2 ) $hItem = _GUICtrlTreeView_Add( $hTreeView, 0, $aItem[1] ) $aLevels[$iLevel] = $hItem ; Add TreeView items For $i = 1 To UBound( $aItems ) - 1 $aItem = StringSplit( $aItems[$i], "|", 2 ) $iLevel = $aItem[0] If $iLevel <> $iLevelPrev Then $hItem = $iLevel > $iLevelPrev ? _GUICtrlTreeView_AddChild( $hTreeView, $aLevels[$iLevelPrev], $aItem[1] ) _ ; A child of the previous level : _GUICtrlTreeView_Add( $hTreeView, $aLevels[$iLevel], $aItem[1] ) ; A sibling of the level $iLevelPrev = $iLevel Else ; $iLevel = $iLevelPrev $hItem = _GUICtrlTreeView_Add( $hTreeView, $aLevels[$iLevel], $aItem[1] ) ; A sibling of the level EndIf $aLevels[$iLevel] = $hItem Next ; $aLevels[$iLevel] contains the last item of that level ; Expand all child items _GUICtrlTreeView_Expand( $hTreeView ) EndFunc Reduced and optimized functionIn the CreateTreeView() function at bottom of the code above, the treeview is created using _GUICtrlTreeView_Add() and _GUICtrlTreeView_AddChild() from GuiTreeView.au3. Both of these functions executes __GUICtrlTreeView_AddItem(), which is an internal function. This internal function fills the TVITEM structures where you can set the LPSTR_TEXTCALLBACK and I_CHILDRENCALLBACK values. The second step is to reduce and optimize the code in CreateTreeView() so that the TVITEM structure is filled in directly in this function. This is the reduced and optimized function (2) Optimized TreeView.au3) expandcollapse popup; Create TreeView with optimized code Func CreateTreeView( $aItems ) ; TreeView item information Local $aItem ; TreeView level information Local $aLevels[100][2], $iLevel = 0, $iLevelPrev = 0 ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level ; TreeView text buffer Local $iBuffer, $tBuffer = DllStructCreate( "wchar Text[50]" ), $pBuffer = DllStructGetPtr( $tBuffer ) ; TreeView insert structure Local $tInsert = DllStructCreate( $tagTVINSERTSTRUCT ), $pInsert = DllStructGetPtr( $tInsert ) DllStructSetData( $tInsert, "InsertAfter", $TVI_LAST ) DllStructSetData( $tInsert, "Mask", $TVIF_TEXT ) DllStructSetData( $tInsert, "Text", $pBuffer ) ; Add TreeView root $aItem = StringSplit( $aItems[0], "|", 2 ) $iBuffer = 2 * StringLen( $aItem[1] ) + 2 DllStructSetData( $tBuffer, "Text", $aItem[1] ) DllStructSetData( $tInsert, "TextMax", $iBuffer ) $aLevels[$iLevel][1] = NULL DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) ; Add TreeView items For $i = 1 To UBound( $aItems ) - 1 $aItem = StringSplit( $aItems[$i], "|", 2 ) $iBuffer = 2 * StringLen( $aItem[1] ) + 2 DllStructSetData( $tBuffer, "Text", $aItem[1] ) DllStructSetData( $tInsert, "TextMax", $iBuffer ) $iLevel = $aItem[0] If $iLevel <> $iLevelPrev Then $aLevels[$iLevel][1] = $iLevel > $iLevelPrev ? $aLevels[$iLevelPrev][0] _ ; A child of the previous level : GUICtrlSendMsg( $idTreeView, $TVM_GETNEXTITEM, $TVGN_PARENT, $aLevels[$iLevel][0] ) ; A sibling of the level $iLevelPrev = $iLevel EndIf DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) Next ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level ; Expand all child items _GUICtrlTreeView_Expand( $hTreeView ) EndFunc Semi-virtual treeviewThe third step is to implement a semi-virtual treeview, where only the tree structure itself but not the item texts are created in CreateTreeView(). Instead of filling in the texts, we set the LPSTR_TEXTCALLBACK value in the TVITEM structure. And then we fill in the texts as needed through a WM_NOTIFY message handler and TVN_GETDISPINFO notifications (3) Semi-Virtual TreeView.au3) expandcollapse popup; Create TreeView structure Func CreateTreeView( $aItems ) ; TreeView level information Local $aLevels[100][2], $iLevel = 0, $iLevelPrev = 0 ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level ; TreeView insert structure Local $tInsert = DllStructCreate( $tagTVINSERTSTRUCT ), $pInsert = DllStructGetPtr( $tInsert ) DllStructSetData( $tInsert, "InsertAfter", $TVI_LAST ) DllStructSetData( $tInsert, "Mask", $TVIF_HANDLE+$TVIF_PARAM+$TVIF_TEXT ) DllStructSetData( $tInsert, "Text", -1 ) ; $LPSTR_TEXTCALLBACK ; Add TreeView root $aLevels[$iLevel][1] = Ptr(0) DllStructSetData( $tInsert, "Param", 0 ) DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) ; Add TreeView items For $i = 1 To UBound( $aItems ) - 1 $iLevel = StringSplit( $aItems[$i], "|", 2 )[0] If $iLevel <> $iLevelPrev Then $aLevels[$iLevel][1] = $iLevel > $iLevelPrev ? $aLevels[$iLevelPrev][0] _ ; A child of the previous level : GUICtrlSendMsg( $idTreeView, $TVM_GETNEXTITEM, $TVGN_PARENT, $aLevels[$iLevel][0] ) ; A sibling of the level $iLevelPrev = $iLevel EndIf DllStructSetData( $tInsert, "Param", $i ) DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) Next ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level ; Expand all child items _GUICtrlTreeView_Expand( $hTreeView ) EndFunc Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Switch HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Case $hTreeView Switch DllStructGetData( $tNMHDR, "Code" ) Case $TVN_GETDISPINFOW ; Display TreeView item text Local Static $tBuffer = DllStructCreate( "wchar Text[50]" ), $pBuffer = DllStructGetPtr( $tBuffer ) Local $tDispInfo = DllStructCreate( $tagNMTVDISPINFO, $lParam ), $sText = StringSplit( $aItems[DllStructGetData($tDispInfo,"Param")], "|", 2 )[1] DllStructSetData( $tBuffer, "Text", $sText ) DllStructSetData( $tDispInfo, "Text", $pBuffer ) DllStructSetData( $tDispInfo, "TextMax", 2 * StringLen( $sText ) + 2 ) EndSwitch EndSwitch #forceref $hWnd, $iMsg, $wParam EndFunc Note that this reduces and optimizes the code in CreateTreeView() even more because the buffer for text strings is no longer needed. Instead, the buffer is populated in the WM_NOTIFY message handler. This technique has the great advantage that only visible treeview items are filled with text strings. Because item texts are only filled in when the items are visible in the treeview, it's necessary to establish a connection between the treeview items and the data source that contains the texts. The data source, which is a simple text file, is loaded into an array. The connection between a treeview item and the data source is the index in this array. Therefore, the array index is stored in the Param field of the TVITEM structure. Virtual treeviewTo make the treeview completely virtual, the fourth and final step is to create and display child items only when required. That is, when an end user clicks the expand button to the left of a treeview item that actually contains child items. And only direct children of this item will be created. If an end user doesn't click an expand button (because these child items are not the ones he's looking for), the child items in question will not be created in the tree structure at all. To make the treeview completely virtual only first level (level-0) items are created in CreateTreeView(). Instead of creating child items, we set the I_CHILDRENCALLBACK value in the TVITEM structure. And then we create child items as needed through a WM_NOTIFY message handler and TVN_GETDISPINFO and TVN_ITEMEXPANDING notifications (4) Virtual TreeView.au3) expandcollapse popup; Create TreeView structure Func CreateTreeView( $aLevel0 ) ; TreeView insert structure Local $tInsert = DllStructCreate( $tagTVINSERTSTRUCT ), $pInsert = DllStructGetPtr( $tInsert ) DllStructSetData( $tInsert, "InsertAfter", $TVI_LAST ) DllStructSetData( $tInsert, "Mask", $TVIF_CHILDREN+$TVIF_HANDLE+$TVIF_PARAM+$TVIF_TEXT ) DllStructSetData( $tInsert, "Parent", NULL ) DllStructSetData( $tInsert, "Children", -1 ) ; $I_CHILDRENCALLBACK DllStructSetData( $tInsert, "Text", -1 ) ; $LPSTR_TEXTCALLBACK ; Add TreeView items For $i = 0 To UBound( $aLevel0 ) - 1 DllStructSetData( $tInsert, "Param", $aLevel0[$i] ) GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) Next EndFunc Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Switch HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Case $hTreeView Switch DllStructGetData( $tNMHDR, "Code" ) Case $TVN_GETDISPINFOW ; Display TreeView item text Local Static $tBuffer = DllStructCreate( "wchar Text[50]" ), $pBuffer = DllStructGetPtr( $tBuffer ) Local $tDispInfo = DllStructCreate( $tagNMTVDISPINFO, $lParam ), $iIndex = DllStructGetData( $tDispInfo, "Param" ), $sText = StringSplit( $aItems[$iIndex], "|", 2 )[3] DllStructSetData( $tBuffer, "Text", $sText ) DllStructSetData( $tDispInfo, "Text", $pBuffer ) DllStructSetData( $tDispInfo, "TextMax", 2 * StringLen( $sText ) + 2 ) DllStructSetData( $tDispInfo, "Children", StringSplit( $aItems[$iIndex], "|", 2 )[1] = 0 ? 0 : 1 ) Case $TVN_ITEMEXPANDINGW ; Create TreeView structure for childs Local $tTreeView = DllStructCreate( $tagNMTREEVIEW, $lParam ) If BitAND( DllStructGetData( $tTreeView, "Action" ), $TVE_EXPAND ) <> $TVE_EXPAND _ Or Int( StringSplit( $aItems[DllStructGetData($tTreeView,"NewParam")], "|", 2 )[2] ) Then Return ; TreeView insert structure Local $tInsert = DllStructCreate( $tagTVINSERTSTRUCT ), $pInsert = DllStructGetPtr( $tInsert ) DllStructSetData( $tInsert, "InsertAfter", $TVI_LAST ) DllStructSetData( $tInsert, "Mask", $TVIF_CHILDREN+$TVIF_HANDLE+$TVIF_PARAM+$TVIF_TEXT ) DllStructSetData( $tInsert, "Parent", DllStructGetData( $tTreeView, "NewhItem" ) ) DllStructSetData( $tInsert, "Children", -1 ) ; $I_CHILDRENCALLBACK DllStructSetData( $tInsert, "Text", -1 ) ; $LPSTR_TEXTCALLBACK ; Add TreeView children Local $iNewIndex = DllStructGetData( $tTreeView, "NewParam" ) + 1 For $i = 0 To StringSplit( $aItems[$iNewIndex-1], "|", 2 )[1] - 1 DllStructSetData( $tInsert, "Param", $iNewIndex + $i ) GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) Next ; Indicate that children have been added $aItems[$iNewIndex-1] = StringReplace( $aItems[$iNewIndex-1], 7, "1" ) EndSwitch EndSwitch #forceref $hWnd, $iMsg, $wParam EndFunc Creating only first level (level-0) items in CreateTreeView() is the crucial step that truly optimizes creation of the treeview. CreateTreeView() in this version is very simple and fast. $aLevel0 is an index of first level (level-0) items. To handle TVN_GETDISPINFO and TVN_ITEMEXPANDING notifications regarding child items, more information is needed in the source file (TreeView-4.txt) 0|000|0|0 0|000|0|1 0|003|0|2 1|000|0|3 1|000|0|This 1|004|0|is 2|000|0|6 2|000|0|a 2|000|0|very 2|002|0|nice 3|000|0|10 3|000|0|TreeView 0|002|0|, (comma) 1|000|0|13 1|000|0|indeed. 0|000|0|15 It's the number of child items in the second field, and a flag to indicate whether child items have already been created in the third field. At top of the TVN_ITEMEXPANDING code section, it's checked if a treeview item with child items is expanded or collapsed and if these child items are already created: Case $TVN_ITEMEXPANDINGW ; Create TreeView structure for childs Local $tTreeView = DllStructCreate( $tagNMTREEVIEW, $lParam ) If BitAND( DllStructGetData( $tTreeView, "Action" ), $TVE_EXPAND ) <> $TVE_EXPAND _ Or Int( StringSplit( $aItems[DllStructGetData($tTreeView,"NewParam")], "|", 2 )[2] ) Then Return The rest of the code in the TVN_ITEMEXPANDING section creates the child items. This code is again very simple and fast. 100,000 items5) 100,000 Items.au3 creates a virtual treeview with 100,000 items based on the 100,000.txt source file. Of course, creating the treeview is lightning fast. 7z-fileThe 7z-file contains source code for UDFs and examples. You need AutoIt 3.3.12 or later. Tested on Windows 7 and Windows 10. Comments are welcome. Let me know if there are any issues. VirtualTreeView.7z Edited February 11, 2023 by LarsJ New 7z-file Letraindusoir, argumentum, ioa747 and 6 others 3 6 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...
LarsJ Posted March 20, 2021 Author Share Posted March 20, 2021 (edited) Multi-line treeview itemsMulti-line treeview items are supported through the iIntegral field in the TVITEM structure and custom draw code. The iIntegral value handles multi-line items in the treeview structure. Custom draw code draws the entire item rectangle, the dotted focus rectangle and the individual multi-line texts. Multi-line treeview items are supported by all treeviews and not just semi-virtual or virtual treeviews. To add a multi-line item with 2, 3 or 4 lines, simply set the value of iIntegral to 2, 3 or 4. Both the width and height of a rectangle that can accommodate all the lines must be calculated in the custom draw code. The height is just 2, 3 or 4 times the height of a single-line item. The width must be set to the width of the widest text string in pixels of the 2, 3, or 4 substrings. The width of a text string in pixels is calculated using the GetTextExtentPoint32W() function. The left position of the rectangle is calculated with _GUICtrlTreeView_GetIndent() and the item level. You'll also need to consider that the width of the entire treeview control may not be large enough to accommodate the longest text strings. Data source for multi-line items (Multiline.txt) 0|0 0|1 0|2 1|3 1|This|Line 2 1|is 2|6 2|a 2|very 2|nice|Line 2|Line 3 3|10 3|TreeView 0|, (comma) 1|13 1|indeed. 0|15 Code in a semi-virtual treeview to create and draw multi-line items (1) Multiline Items.au3) expandcollapse popup; Create TreeView structure Func CreateTreeView( $aItems ) ; TreeView item information Local $aItem, $iItem ; TreeView level information Local $aLevels[100][2], $iLevel = 0, $iLevelPrev = 0 ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level ; TreeView insert structure Local $tInsert = DllStructCreate( $tagTVINSERTSTRUCT ), $pInsert = DllStructGetPtr( $tInsert ) DllStructSetData( $tInsert, "InsertAfter", $TVI_LAST ) DllStructSetData( $tInsert, "Mask", $TVIF_HANDLE+$TVIF_PARAM+$TVIF_TEXT+$TVIF_INTEGRAL ) DllStructSetData( $tInsert, "Text", -1 ) ; $LPSTR_TEXTCALLBACK ; Add TreeView root $aItem = StringSplit( $aItems[0], "|", 2 ) $iItem = UBound( $aItem ) $aLevels[$iLevel][1] = NULL DllStructSetData( $tInsert, "Param", 0 ) DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) DllStructSetData( $tInsert, "Integral", $iItem > 2 ? $iItem - 1 : 1 ) $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) ; Add TreeView items For $i = 1 To UBound( $aItems ) - 1 $aItem = StringSplit( $aItems[$i], "|", 2 ) $iItem = UBound( $aItem ) $iLevel = $aItem[0] If $iLevel <> $iLevelPrev Then $aLevels[$iLevel][1] = $iLevel > $iLevelPrev ? $aLevels[$iLevelPrev][0] _ ; A child of the previous level : GUICtrlSendMsg( $idTreeView, $TVM_GETNEXTITEM, $TVGN_PARENT, $aLevels[$iLevel][0] ) ; A sibling of the level $iLevelPrev = $iLevel EndIf DllStructSetData( $tInsert, "Param", $i ) DllStructSetData( $tInsert, "Parent", $aLevels[$iLevel][1] ) DllStructSetData( $tInsert, "Integral", $iItem > 2 ? $iItem - 1 : 1 ) $aLevels[$iLevel][0] = GUICtrlSendMsg( $idTreeView, $TVM_INSERTITEMW, 0, $pInsert ) Next ; $aLevels[$iLevel][0]/[1] contains the last item/parent of that level EndFunc Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Switch HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Case $hTreeView Switch DllStructGetData( $tNMHDR, "Code" ) Case $TVN_GETDISPINFOW ; Display TreeView item text Local Static $tBuffer = DllStructCreate( "wchar Text[50]" ), $pBuffer = DllStructGetPtr( $tBuffer ) Local $tDispInfo = DllStructCreate( $tagNMTVDISPINFO, $lParam ), $sText = StringSplit( $aItems[DllStructGetData($tDispInfo,"Param")], "|", 2 )[1] DllStructSetData( $tBuffer, "Text", $sText ) DllStructSetData( $tDispInfo, "Text", $pBuffer ) DllStructSetData( $tDispInfo, "TextMax", 2 * StringLen( $sText ) + 2 ) Case $NM_CUSTOMDRAW Local $tCustomDraw = DllStructCreate( $tagNMTVCUSTOMDRAW, $lParam ) Switch DllStructGetData( $tCustomDraw, "DrawStage" ) ; The current drawing stage Case $CDDS_PREPAINT ; Before the paint cycle begins Return $CDRF_NOTIFYITEMDRAW ; Notify the parent before painting an item Case $CDDS_ITEMPREPAINT ; Before painting an item If UBound( StringSplit( $aItems[DllStructGetData($tCustomDraw,"ItemParam")], "|", 2 ) ) > 2 Then _ Return $CDRF_NOTIFYPOSTPAINT ; Notify the parent after painting an item ; Draw multiline item texts Case $CDDS_ITEMPOSTPAINT ; After painting an item Local Static $iTVIndent = _GUICtrlTreeView_GetIndent( $hTreeView ), $tSize = DllStructCreate( $tagSIZE ), $hBrushHighLight = _WinAPI_GetSysColorBrush( $COLOR_HIGHLIGHT ), $hBrushButtonFace = _WinAPI_GetSysColorBrush( $COLOR_BTNFACE ), $hBrushWhite = _WinAPI_CreateSolidBrush( 0xFFFFFF ) Local $hDC = DllStructGetData( $tCustomDraw, "HDC" ), $tRect = DllStructCreate( $tagRECT, DllStructGetPtr( $tCustomDraw, "Left" ) ), $aItem = StringSplit( $aItems[DllStructGetData($tCustomDraw,"ItemParam")], "|", 2 ), $iItem = UBound( $aItem ), $iMaxTextLen = 0, $iLeft = $iTVIndent * ( $aItem[0] + 1 ) + 3, $iRectWidth = DllStructGetData( $tCustomDraw, "Right" ) - $iLeft, $iTop = DllStructGetData( $tRect, "Top" ), $iItemState = DllStructGetData( $tCustomDraw, "ItemState" ) ; Longest text in pixels of all item texts For $i = 1 To $iItem - 1 DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $aItem[$i], "int", StringLen( $aItem[$i] ), "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 If DllStructGetData( $tSize, "X" ) + 1 > $iMaxTextLen Then $iMaxTextLen = DllStructGetData( $tSize, "X" ) + 1 Next ; Rectangle that includes all item texts If $iMaxTextLen + 4 > $iRectWidth Then _ $iMaxTextLen = $iRectWidth - 4 DllStructSetData( $tRect, "Left", $iLeft ) DllStructSetData( $tRect, "Right", $iLeft + $iMaxTextLen + 4 ) DllStructSetData( $tRect, "Bottom", $iTop + 18 * ( $iItem - 1 ) ) DllCall( "gdi32.dll", "int", "SetBkMode", "handle", $hDC, "int", $TRANSPARENT ) ; _WinAPI_SetBkMode() Switch BitAND( $iItemState, $CDIS_SELECTED + $CDIS_FOCUS ) Case $CDIS_SELECTED + $CDIS_FOCUS DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $hBrushHighLight ) ; _WinAPI_FillRect() DllCall( "user32.dll", "bool", "DrawFocusRect", "handle", $hDC, "struct*", $tRect ) ; _WinAPI_DrawFocusRect() DllCall( "gdi32.dll", "INT", "SetTextColor", "handle", $hDC, "INT", 0xFFFFFF ) ; _WinAPI_SetTextColor() Case $CDIS_SELECTED DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $hBrushButtonFace ) ; _WinAPI_FillRect() Case $CDIS_FOCUS Case Else DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $hBrushWhite ) ; _WinAPI_FillRect() EndSwitch ; Left start position for item texts DllStructSetData( $tRect, "Left", $iLeft + 2 ) ; Draw all item texts For $i = 1 To UBound( $aItem ) - 1 DllStructSetData( $tRect, "Top", $iTop + 18 * ( $i - 1 ) + 1 ) DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $aItem[$i], "int", -1, "struct*", $tRect, "uint", $DT_LEFT+$DT_WORD_ELLIPSIS ) ; _WinAPI_DrawText() Next EndSwitch EndSwitch EndSwitch #forceref $hWnd, $iMsg, $wParam EndFunc Store MaxTextLen in data sourceBecause the width of the longest text string in pixels ($iMaxTextLen) must be calculated each time a multi-line item needs to be redrawn, it can be an advantage to store this width directly in the data source. Multiline-2.txt: 0|000|0 0|000|1 0|000|2 1|000|3 1|000|This|Line 2 1|000|is 2|000|6 2|000|a|A somewhat long new line 2|000|very 2|000|nice|A TreeView item with three lines|Line 3 3|000|10 3|000|TreeView 0|000|, (comma) 1|000|13 1|000|indeed. 0|000|15 2) Store MaxTextLen.au3: ; Cleanup GUIDelete( $hGui ) If $bSaveItems Then _FileWriteFromArray( "Multiline-2.txt", $aItems ) $aItem = StringSplit( $aItems[DllStructGetData($tCustomDraw,"ItemParam")], "|", 2 ) $iMaxTextLen = $aItem[1]+0 ; Longest text in pixels of all item texts If Not $iMaxTextLen Then For $i = 2 To $iItem - 1 DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $aItem[$i], "int", StringLen( $aItem[$i] ), "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 If DllStructGetData( $tSize, "X" ) + 1 > $iMaxTextLen Then $iMaxTextLen = DllStructGetData( $tSize, "X" ) + 1 Next $bSaveItems = True $iIndex = DllStructGetData( $tCustomDraw, "ItemParam" ) $aItems[$iIndex] = StringReplace( $aItems[$iIndex], 3, StringFormat( "%03i", $iMaxTextLen ) ) EndIf Too narrow treeview control3) Store MaxTextLen.au3 is similar to the example above except that the treeview control is too narrow for the longest text strings. New 7z-file at bottom of first post. The first set of examples in 1) Virtual TreeView\ has all been updated with some very minor changes. Edited April 2, 2021 by LarsJ Orange header argumentum, mLipok and ptrex 3 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...
Letraindusoir Posted March 22, 2021 Share Posted March 22, 2021 Excellent post, it makes it easier and faster to create a treeview. Thanks LarsJ ! If it could add functions such as drag-drop, add-delete-items, edit-Item-text and so on, it's would more perfect I've been looking for a similar example of a treeview that can dragdrop, edit, and rearrange items freely Link to comment Share on other sites More sharing options...
LarsJ Posted March 26, 2021 Author Share Posted March 26, 2021 A virtual treeview with hundreds of thousands of items will most likely be used to provide some sort of overview of data, while it's less likely that it'll be used to correct a few individual items. If there's a need to manually correct a few individual items, then it'll be better to create a treeview that contains only those few items that it's about. When it comes to (human) manual correction of data, it's of course only about a very small amount of data. It's simply not possible to manually correct a very large amount of data. And when it comes to only a small amount of data, there's no problem in using a conventional treeview where all necessary functionality is already implemented. When it comes to very large amounts of data, then it must be a requirement that data is handled completely automatically. At least what I'm doing with virtual treeviews here is meant to provide some sort of overview of data. Therefore, it isn't my plan to code functions to handle individual items. Another problem with updating individual items in a large virtual treeview is that the update must take place in the data source. Data isn't stored in the treeview itself. But to update a large array (e.g. move array elements up/down when a treeview item is deleted/added) in an interpreted language like AutoIt isn't fast. But even worse is that since the array index is stored in the Param field of the TVITEM structure, moving array elements up/down will invalidate many of these Param values. And it'll ruin the whole idea by using a virtual treeview. Item imagesSet the iImage and iSelectedImage fields in the TVITEM structure to the value $I_IMAGECALLBACK to use item images in a virtual treeview. And then set the index in the image list of the item image when responding to TVN_GETDISPINFO notifications. Here, the item image index in the image list is indicated in the second column (Item Images.txt) 0|0|0 0|0|1 0|0|2 1|0|3 1|0|This|Line 2 1|0|is 2|1|6 2|1|a 2|1|very 2|1|nice|Line 2|Line 3 3|1|10 3|2|TreeView 0|2|, (comma) 1|2|13 1|2|indeed. 0|2|15 The same item image is used for both selected and unselected treeview items. Code to create image list: ; Create small image ImageList Local $hImageList = _GUIImageList_Create( 16, 16, 5, 1 ) ; Add small images to ImageList _GUIImageList_Add( $hImageList, _WinAPI_CreateSolidBitmap( $hGui, 0xFF0000, 16, 16 ) ) ; Index 0, Red _GUIImageList_Add( $hImageList, _WinAPI_CreateSolidBitmap( $hGui, 0xFF00FF, 16, 16 ) ) ; Index 1, Magenta _GUIImageList_Add( $hImageList, _WinAPI_CreateSolidBitmap( $hGui, 0x0000FF, 16, 16 ) ) ; Index 2, Blue ; Add ImageList to TreeView _GUICtrlTreeView_SetNormalImageList( $hTreeView, $hImageList ) Set Image and SelectedImage fields in the TVITEM structure: DllStructSetData( $tInsert, "Image", -1 ) ; $I_IMAGECALLBACK DllStructSetData( $tInsert, "SelectedImage", -1 ) ; $I_IMAGECALLBACK Respond to TVN_GETDISPINFO notifications: Case $TVN_GETDISPINFOW ; Display TreeView item text and image Local Static $tBuffer = DllStructCreate( "wchar Text[50]" ), $pBuffer = DllStructGetPtr( $tBuffer ) Local $tDispInfo = DllStructCreate( $tagNMTVDISPINFO, $lParam ), $aItem = StringSplit( $aItems[DllStructGetData($tDispInfo,"Param")], "|", 2 ) DllStructSetData( $tBuffer, "Text", $aItem[2] ) DllStructSetData( $tDispInfo, "Text", $pBuffer ) DllStructSetData( $tDispInfo, "TextMax", 2 * StringLen( $aItem[2] ) + 2 ) DllStructSetData( $tDispInfo, "Image", $aItem[1] ) DllStructSetData( $tDispInfo, "SelectedImage", $aItem[1] ) Multi-line itemsFor multi-line items, the rectangle containing all text lines should be shifted to the right to make room for the item image. Ie. the $iLeft value of the rectangle should be increased by the width of the image plus a few pixels: ; $iLeft without item image $iLeft = $iTVIndent * ( $aItem[0] + 1 ) + 3 ; $iLeft with item image $iLeft = $iTVIndent * ( $aItem[0] + 1 ) + 16 + 3 + 3 New 7z-file at bottom of first post. argumentum and mLipok 1 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...
LarsJ Posted March 28, 2021 Author Share Posted March 28, 2021 Performance testsThe examples in first post have been used for performance tests on the basis of a common source file, 10100.txt, with 10,100 treeview items of which 100 are root items. In addition, the source file 10000.txt with 1 root item and 9,999 direct child items is used to test the creation of direct child items in a true virtual treeview. The tests are run as 64 bit code on Windows 7 and 10. Results on Windows 7 with AutoIt 3.3.14.2: 1) Conventional TreeView.au3 CreateTreeView(): 1084.16993786727 2) Optimized TreeView.au3 CreateTreeView(): 121.195523739788 3) Semi-Virtual TreeView.au3 CreateTreeView(): 100.011054067689 4) Virtual TreeView.au3 CreateTreeView(): 4.07172012097971 5) Virtual TreeView 9999 Child Items.au3 Create 9999 Child Items: 254.070404160541 The true virtual tree view in test 4 is created very fast because there are only 100 root items. On the other hand, the creation of 9,999 direct child items in test 5 is relatively slow. Results on Windows 10 with AutoIt 3.3.15.3 Beta: 1) Conventional TreeView.au3 CreateTreeView(): 1519.9362 2) Optimized TreeView.au3 CreateTreeView(): 212.4225 3) Semi-Virtual TreeView.au3 CreateTreeView(): 183.8063 4) Virtual TreeView.au3 CreateTreeView(): 18.1912 5) Virtual TreeView 9999 Child Items.au3 Create 9999 Child Items: 455.3943 Note that the tests here without exception are all a lot slower than the tests on Windows 7. Probably because Windows 10 is a more advanced, complex and sophisticated operating system than Windows 7 and therefore runs a lot more code to perform the same task. Structure of a semi-virtual treeviewIn 6) Semi-Virtual TreeView Structure.au3, the code line GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") is commented out. This means that only the tree structure is created based on information in the TVITEM structures. The tree structure itself is drawn by default code, but the texts depend on TVN_GETDISPINFO notifications in WM_NOTIFY messages, and are not drawn. In the image below, the first root item is expanded: New 7z-file at bottom of first post. mLipok, argumentum and Letraindusoir 1 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...
LarsJ Posted April 2, 2021 Author Share Posted April 2, 2021 MiscellaneousThe second post above is about multi-line treeview items that are supported by all treeviews through the iIntegral field in the TVITEM structure and custom draw code. _GUICtrlTreeView_SetItemHeight()Setting the iIntegral value is handled by _GUICtrlTreeView_SetItemHeight() in GuiTreeView.au3. But the accompanying example in the help file only shows how the first line of a multi-line text is drawn with default code. It doesn't show how subsequent lines are drawn with custom draw code. And to get a good result, it's also necessary to draw the first line with custom draw code. This is demonstrated in Miscellaneous\1) _GUICtrlTreeView_SetItemHeight.au3: expandcollapse popup#AutoIt3Wrapper_Au3Check_Parameters=-d -w- 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=Y Opt( "MustDeclareVars", 1 ) #include <GUIConstantsEx.au3> #include <GuiTreeView.au3> #include <WindowsConstants.au3> Global $idTreeView, $hTreeView, $aItems = FileReadToArray( "Multiline.txt" ) Example() Func Example() ; TreeView style Local $iStyle = BitOR( $TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS, $TVS_CHECKBOXES ), $ahItem[6] ; Create GUI GUICreate( "TreeView Set Item Height", 400, 300 ) ; Create TreeView $idTreeView = GUICtrlCreateTreeView( 2, 2, 396, 268, $iStyle, $WS_EX_CLIENTEDGE ) $hTreeView = GUICtrlGetHandle( $idTreeView ) For $x = 0 To UBound( $ahItem ) - 1 $ahItem[$x] = _GUICtrlTreeView_AddChild( $idTreeView, NULL, StringFormat( "[%02d] New Item", $x + 1 ) ) Next _GUICtrlTreeView_SetItemParam( $idTreeView, $ahItem[2], 2 ) ; Index in $aItems _GUICtrlTreeView_SetItemHeight( $idTreeView, $ahItem[2], 2 ) ; $iIntegral ; Register WM_NOTIFY message handler GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" ) ; Show GUI GUISetState( @SW_SHOW ) ; Loop until the user exits Do Until GUIGetMsg() = $GUI_EVENT_CLOSE GUIDelete() EndFunc Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam ) Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Switch HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Case $hTreeView Switch DllStructGetData( $tNMHDR, "Code" ) Case $NM_CUSTOMDRAW Local $tCustomDraw = DllStructCreate( $tagNMTVCUSTOMDRAW, $lParam ) Switch DllStructGetData( $tCustomDraw, "DrawStage" ) ; The current drawing stage Case $CDDS_PREPAINT ; Before the paint cycle begins Return $CDRF_NOTIFYITEMDRAW ; Notify the parent before painting an item Case $CDDS_ITEMPREPAINT ; Before painting an item If UBound( StringSplit( $aItems[DllStructGetData($tCustomDraw,"ItemParam")], "|", 2 ) ) > 2 Then _ Return $CDRF_NOTIFYPOSTPAINT ; Notify the parent after painting an item ; Draw multiline item texts Case $CDDS_ITEMPOSTPAINT ; After painting an item Local Static $iTVIndent = _GUICtrlTreeView_GetIndent( $hTreeView ), $tSize = DllStructCreate( $tagSIZE ), $hBrushHighLight = _WinAPI_GetSysColorBrush( $COLOR_HIGHLIGHT ), $hBrushButtonFace = _WinAPI_GetSysColorBrush( $COLOR_BTNFACE ), $hBrushWhite = _WinAPI_CreateSolidBrush( 0xFFFFFF ) Local $hDC = DllStructGetData( $tCustomDraw, "HDC" ), $tRect = DllStructCreate( $tagRECT, DllStructGetPtr( $tCustomDraw, "Left" ) ), $aItem = StringSplit( $aItems[DllStructGetData($tCustomDraw,"ItemParam")], "|", 2 ), $iItem = UBound( $aItem ), $iMaxTextLen = 0, $iLeft = $iTVIndent * ( $aItem[0] + 1 ) + 16, $iRectWidth = DllStructGetData( $tCustomDraw, "Right" ) - $iLeft, $iTop = DllStructGetData( $tRect, "Top" ), $iItemState = DllStructGetData( $tCustomDraw, "ItemState" ) ; Longest text in pixels of all item texts For $i = 1 To $iItem - 1 DllCall( "gdi32.dll", "bool", "GetTextExtentPoint32W", "handle", $hDC, "wstr", $aItem[$i], "int", StringLen( $aItem[$i] ), "struct*", $tSize ) ; _WinAPI_GetTextExtentPoint32 If DllStructGetData( $tSize, "X" ) + 1 > $iMaxTextLen Then $iMaxTextLen = DllStructGetData( $tSize, "X" ) + 1 Next ; Rectangle that includes all item texts If $iMaxTextLen + 4 > $iRectWidth Then _ $iMaxTextLen = $iRectWidth - 4 DllStructSetData( $tRect, "Left", $iLeft ) DllStructSetData( $tRect, "Right", $iLeft + $iMaxTextLen + 4 ) DllStructSetData( $tRect, "Bottom", $iTop + 18 * ( $iItem - 1 ) ) DllCall( "gdi32.dll", "int", "SetBkMode", "handle", $hDC, "int", $TRANSPARENT ) ; _WinAPI_SetBkMode() Switch BitAND( $iItemState, $CDIS_SELECTED + $CDIS_FOCUS ) Case $CDIS_SELECTED + $CDIS_FOCUS DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $hBrushHighLight ) ; _WinAPI_FillRect() DllCall( "user32.dll", "bool", "DrawFocusRect", "handle", $hDC, "struct*", $tRect ) ; _WinAPI_DrawFocusRect() DllCall( "gdi32.dll", "INT", "SetTextColor", "handle", $hDC, "INT", 0xFFFFFF ) ; _WinAPI_SetTextColor() Case $CDIS_SELECTED DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $hBrushButtonFace ) ; _WinAPI_FillRect() Case $CDIS_FOCUS Case Else DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $hBrushWhite ) ; _WinAPI_FillRect() EndSwitch ; Left start position for item texts DllStructSetData( $tRect, "Left", $iLeft + 2 ) ; Draw all item texts For $i = 1 To UBound( $aItem ) - 1 DllStructSetData( $tRect, "Top", $iTop + 18 * ( $i - 1 ) + 1 ) DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $aItem[$i], "int", -1, "struct*", $tRect, "uint", $DT_LEFT+$DT_WORD_ELLIPSIS ) ; _WinAPI_DrawText() Next EndSwitch EndSwitch EndSwitch #forceref $hWnd, $iMsg, $wParam EndFunc Note that in my example, I've removed the $TVS_EDITLABELS style because the Edit control by default only supports editing the first line of a multi-line item. To use $TVS_EDITLABELS with multi-line items, the Edit control should of course support editing of all the lines. New 7z-file at bottom of first post. 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...
LarsJ Posted April 2, 2021 Author Share Posted April 2, 2021 UDF versionsThe last section planned in this example about virtual treeviews is UDF versions of the code. The functional requirements in the example were in order of priority: An external data source needed to implement a virtual treeview Virtual treeviews to speed up the creation of large treeviews Multi-line treeview items to avoid overly long text lines Other visual functionality supported by virtual treeviews An external data source is fundamental to any virtual control. First post is about creating a virtual treeview based on an external data source. Because the Microsoft documentation on virtual treeviews is very brief, the easiest approach is to start with a conventional treeview, then reduced and optimized code where the TVITEM structures are filled in directly, a semi-virtual treeview where only the item texts are virtual but not the tree structure itself, and finally a true virtual treeview where also the tree structure is virtual except for root items. The second post is about multi-line treeview items that are supported by all treeviews through the iIntegral field in the TVITEM structure and custom draw code. In the post just above, it's demonstrated that multi-line items are also useful in conventional treeviews. Other visual functionality that can be implemented in a true virtual treeview is limited to what can be handled through default drawing code, TVN_GETDISPINFO notifications and custom draw code. Fourth post about Item images shows that images are supported by default drawing code when the index in the image list is set through TVN_GETDISPINFO notifications. Checkboxes are fully supported by default drawing code. However, for multi-line items, the rectangle containing all lines must be shifted to the right to make room for images and checkboxes. In Custom drawn TreeViews, it's demonstrated how to set text and background color as well as font properties through custom draw code. This example is also valid for virtual treeviews. Features in a UDFThe features that will be implemented in a UDF will be limited to treeviews created solely on the basis of an external data source. Other than that features are likely to be coded for all four types of tree views (conventional, optimized, semi-virtual, and virtual). The fact that multi-line items work in a conventional treeview is a reasonably good reason to include a few functions for conventional treeviews. Another reason to include conventional treeviews in a UDF is that all treeview features only work in a conventional treeview. All features also work in a treeview based on optimized code. That type is interesting in a UDF because of the speed. A semi-virtual treeview is required if the entire treeview structure is to be created in advance so that only item texts and images can be virtual. Therefore, this type should be included in a UDF. A true virtual treeview is the Formula One version of the treeviews. This is the version the whole example is about. And it's the absolutely essential version of a UDF. So far, not a single line has been coded in a UDF. So a UDF isn't just around the corner. A UDF will be presented when it's ready. mLipok, Danyfirex and argumentum 3 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...
LarsJ Posted January 8, 2023 Author Share Posted January 8, 2023 (edited) Real virtual treeviews In first part of Virtual treeviews, only the number of child items for a given node/parent was specified. When only the number of child items is specified, these items must appear in a continuous and uninterrupted row of child items. And only one item can be a node/parent, namely the last one in the row. To work around this limitation, it's necessary to specify child item lists instead of just the number of child items. For each node/parent a list is needed that for each child item indicates the row number in the source file where information about this child item can be found. Thus the source file must also contain information about these child item lists. All code is located in the folder Examples\Part 2\1) Real Virtual TreeViews. Simple example (1) Simple\) Show the two treeviews by double-clicking TVSourceDisplayPlain.au3 and TVSourceDisplayVirtual.au3. This source file is sufficient for a plain or semi-virtual treeview (3 levels, 5 items, Plain.txt) 00|Item0 01|Item1 02|Item2 01|Item3 00|Item4 In a plain treeview texts are stored in the item structures. In a semi-virtual treeview texts are virtual and stored only in the source file. Therefore, a semi-virtual treeview is faster to create than a plain treeview. For both types, the treeview structure is created when the treeview is created. In a virtual treeview, more information is needed (3 levels, 5 items, Virtual.txt) 00| | 7| |Item0 01| 0| 1| |Item1 02| 1| | |Item2 01| 0| | |Item3 00| | | |Item4 Level 0 parents and items = 2 0:1|3| 4: Level 1 parents = 1 0|5 0:7|2 1:11|1 A virtual treeview means a true virtual treeview where all child items and texts are virtual. Information about child items and texts is stored in the source file. Only root items (first level items) are created when the treeview is created. Because the number of root items is usually low, it's very fast to create a virtual treeview. The actual treeview item information at top of the source file is a |-separated list with 5 fields: 1 Treeview item level 2 Row number in source file containing parent item 3 Row number in source file containing child item list 4 Indication of expanded parent 5 Treeview item text The information at bottom of the source file is divided into several sections. There is a section for "Level 0 parents and items", "Level 1 parents", "Level 2 parents", etc. The very last section is a summary section. Level 0 parents and items = 2 The child item list for Item0 (at level 0 = first level = root level) is found in row 7 (zero-based) in the source file. Data in row 7 is 0:1|3|. 0 is the row number where the list is used. 1|3| is the child item list itself. Item0 has 2 direct childs in rows 1 and 3. Data in row 8 is 4:. Item4 in row 4 is a root item without any childs. Level 1 parents = 1 Since the current treeview has 3 levels (level 0, 1 and 2 zero-based), a node/parent at level 1 (second last level) can only have ordinary child items (ie. no nodes/parents). Row 1 in the source file contains a level 1 node/parent. Because the child items are ordinary child items, it's enough to indicate the number of child items. The node/parent in row 1 has 1 child item. This number is stated directly in field 3 instead of the row number for the child item list. Since no child item lists are needed for level 1 (second last level) nodes/parents, the section named "Level 1 parents = 1" is empty. Level 2 parents Because there are only 3 levels, there are no node/parent items at level 2 (zero-based). There are only child items. No child lists for "Level 2 parents". Summary section The lines at bottom of the source file is a summary section. 0|5 means that the actual treeview item information starts in row 0 and includes 5 rows. 0:7|2 means that child item lists for level 0 starts in row 7 and includes 2 rows. 1:11|1 means that child item lists for level 1 starts in row 11 and includes 1 row. But as mentioned above, it's not necessary to specify child item lists for second last level. The last line in the source file 1:11|1 is instead used to calculate the total number of levels. The number of levels is the number before : plus 1. In this case 2 levels (1+1=2 (zero-based)). TVSourceFile.au3 (Includes\TVSourceFile.au3) TVSourceFile.au3 is a so far incomplete version of a UDF to handle treeview source files. This is the function list at top of the file: ; Functions ; --------------------------------- ; TVSourceCreatePlain() Create random plain source file for non-virtual treeview ; TVSourceCreatePlainDbg() Create random plain source file for non-virtual treeview. Debug version. ; TVSourceCreatePlainEx() Based on recursive function with support for 100 levels ; TVSourceCreatePlainExDbg() Based on recursive function with support for 100 levels. Debug version. ; TVSourceCreatePlainExConst() Create constant plain source file for non-virtual treeview. Debug version. Constant source file. ; TVSourceCreatePlainExConstCount() Count number of treeview items generated by TVSourceCreatePlainExConst() above ; TVSourceCreateVirtual() Create random source file for virtual treeview ; TVSourceCreateVirtualDbg() Create random source file for virtual treeview. Debug version. Contains code comments. <<<<<<<<<< ; ; TVSourceConvertPlainToVirtual() Convert plain source file for non-virtual treeview to source file for virtual treeview ; TVSourceConvertVirtualToPlain() Convert source file for virtual treeview to plain source file for non-virtual treeview ; ; TVSourceDisplayPlain() Display non-virtual treeview from plain source file ; TVSourceDisplayVirtual() Display virtual treeview from source file The functions TVSourceCreatePlain(), TVSourceCreatePlainDbg(), TVSourceCreateVirtual() and TVSourceCreateVirtualDbg() are implemented through loops that can generate source files and thus treeviews with up to 10 levels. The Ex-functions TVSourceCreatePlainEx(), TVSourceCreatePlainExDbg() and TVSourceCreatePlainExConst() are based on recursive functions that can generate source files with up to 100 levels. The Dbg- and Const-functions contain debug information in the item texts in the form of an indication of whether an item is a node/parent or a plain item as well as row index in source file and treeview. The other functions generate random item texts. All functions except TVSourceCreatePlainExConst() generate random treeview structures with a random number of items. True virtual treeviews are limited to 10,000,000 items. TVSourceCreatePlainExConst() generates a constant treeview in such a way that the same input parameters will always result in the same treeview. TVSourceCreatePlainExConstCount() calculates the number of items in these treeviews. TVSourceConvertPlainToVirtual() and TVSourceConvertVirtualToPlain() convert back and forth between plain and virtual treeviews. Due to a complicated structure of a source file for a virtual treeview, it's difficult to update the treeview by editing the source file. The idea is to first convert the virtual file to a plain file. Then update the plain source file. And finally convert back to a virtual file. TVSourceDisplayPlain() and TVSourceDisplayVirtual() display treeviews in a GUI. Function examples (2) Sources\)2) Sources\ contains examples of the use of each function. Run the examples in SciTE with F5. Treeview source files are stored in the Sources\ top folder. These are the examples for TVSourceCreatePlainExConst() and TVSourceCreatePlainExConstCount(). 4) TVSourceCreatePlainExConst.au3: #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=Y Opt( "MustDeclareVars", 1 ) #include "..\Includes\TVSourceFile.au3" Global $sSources = "..\..\..\..\Sources\" ; With many levels and thus many treeview items, it can take some time to generate the source file. It may also ; take a long time to create the entire structure for a non-virtual treeview before it can be displayed in the GUI. ConsoleWrite( "TVSourceCreatePlainExConst( 6, 4, 4, ...) Creating..." & @CRLF ) If TVSourceCreatePlainExConst( 6, 4, 4, $sSources & "6 levels, 26,071 items, Plain, debug, const.txt" ) Then ConsoleWrite( "TVSourceCreatePlainExConst( 6, 4, 4, ...) Displaying..." & @CRLF ) If Not TVSourceDisplayPlain( $sSources & "6 levels, 26,071 items, Plain, debug, const.txt" ) Then _ ConsoleWrite( "TVSourceDisplayPlain: @error = " & @error & @CRLF ) Else ConsoleWrite( "TVSourceCreatePlainExConst: @error = " & @error & @CRLF ) EndIf 5) TVSourceCreatePlainExConstCount.au3: #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=Y Opt( "MustDeclareVars", 1 ) #include "..\Includes\TVSourceFile.au3" Example() Func Example() Local $iItems0, $iCount For $iLevels = 1 To 10 For $iMultiplier = 2 To 10 For $iItems = 1 To 10 $iItems0 = $iItems * $iMultiplier If Not TVSourceCreatePlainExConstCount( $iLevels, $iItems0, $iMultiplier, $iCount ) Then ConsoleWrite( "TVSourceCreatePlainExConstCount: @error = " & @error & " " & _ StringFormat( "%3i, %3i, %3i", $iLevels, $iItems0, $iMultiplier ) & @CRLF ) ExitLoop EndIf ConsoleWrite( "$iLevels, $iItems0, $iMultiplier, $iCount = " & _ StringFormat( "%3i, %3i, %3i, %8i", $iLevels, $iItems0, $iMultiplier, $iCount ) & @CRLF ) Next Next Next EndFunc This is the last part of the output: expandcollapse popup$iLevels, $iItems0, $iMultiplier, $iCount = 7, 2, 2, 6787 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 4, 2, 13574 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 6, 2, 20361 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 8, 2, 27148 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 10, 2, 33935 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 12, 2, 40722 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 14, 2, 47509 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 16, 2, 54296 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 18, 2, 61083 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 20, 2, 67870 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 3, 3, 52145 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 6, 3, 104290 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 9, 3, 156435 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 12, 3, 208580 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 15, 3, 260725 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 18, 3, 312870 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 21, 3, 365015 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 24, 3, 417160 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 27, 3, 469305 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 30, 3, 521450 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 4, 4, 227671 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 8, 4, 455342 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 12, 4, 683013 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 16, 4, 910684 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 20, 4, 1138355 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 24, 4, 1366026 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 28, 4, 1593697 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 32, 4, 1821368 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 36, 4, 2049039 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 40, 4, 2276710 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 5, 5, 741169 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 10, 5, 1482338 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 15, 5, 2223507 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 20, 5, 2964676 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 25, 5, 3705845 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 30, 5, 4447014 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 35, 5, 5188183 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 40, 5, 5929352 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 45, 5, 6670521 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 50, 5, 7411690 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 6, 6, 1999691 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 12, 6, 3999382 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 18, 6, 5999073 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 24, 6, 7998764 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 30, 6, 9998455 TVSourceCreatePlainExConstCount: @error = 2 7, 36, 6 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 7, 7, 4724257 $iLevels, $iItems0, $iMultiplier, $iCount = 7, 14, 7, 9448514 TVSourceCreatePlainExConstCount: @error = 2 7, 21, 7 TVSourceCreatePlainExConstCount: @error = 2 7, 8, 8 TVSourceCreatePlainExConstCount: @error = 2 7, 9, 9 TVSourceCreatePlainExConstCount: @error = 2 7, 10, 10 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 2, 2, 52147 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 4, 2, 104294 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 6, 2, 156441 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 8, 2, 208588 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 10, 2, 260735 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 12, 2, 312882 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 14, 2, 365029 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 16, 2, 417176 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 18, 2, 469323 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 20, 2, 521470 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 3, 3, 455345 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 6, 3, 910690 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 9, 3, 1366035 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 12, 3, 1821380 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 15, 3, 2276725 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 18, 3, 2732070 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 21, 3, 3187415 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 24, 3, 3642760 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 27, 3, 4098105 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 30, 3, 4553450 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 4, 4, 2223511 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 8, 4, 4447022 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 12, 4, 6670533 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 16, 4, 8894044 TVSourceCreatePlainExConstCount: @error = 2 8, 20, 4 $iLevels, $iItems0, $iMultiplier, $iCount = 8, 5, 5, 7998769 TVSourceCreatePlainExConstCount: @error = 2 8, 10, 5 TVSourceCreatePlainExConstCount: @error = 2 8, 6, 6 TVSourceCreatePlainExConstCount: @error = 2 8, 7, 7 TVSourceCreatePlainExConstCount: @error = 2 8, 8, 8 TVSourceCreatePlainExConstCount: @error = 2 8, 9, 9 TVSourceCreatePlainExConstCount: @error = 2 8, 10, 10 $iLevels, $iItems0, $iMultiplier, $iCount = 9, 2, 2, 455347 $iLevels, $iItems0, $iMultiplier, $iCount = 9, 4, 2, 910694 $iLevels, $iItems0, $iMultiplier, $iCount = 9, 6, 2, 1366041 $iLevels, $iItems0, $iMultiplier, $iCount = 9, 8, 2, 1821388 $iLevels, $iItems0, $iMultiplier, $iCount = 9, 10, 2, 2276735 $iLevels, $iItems0, $iMultiplier, $iCount = 9, 12, 2, 2732082 $iLevels, $iItems0, $iMultiplier, $iCount = 9, 14, 2, 3187429 $iLevels, $iItems0, $iMultiplier, $iCount = 9, 16, 2, 3642776 $iLevels, $iItems0, $iMultiplier, $iCount = 9, 18, 2, 4098123 $iLevels, $iItems0, $iMultiplier, $iCount = 9, 20, 2, 4553470 $iLevels, $iItems0, $iMultiplier, $iCount = 9, 3, 3, 4447025 $iLevels, $iItems0, $iMultiplier, $iCount = 9, 6, 3, 8894050 TVSourceCreatePlainExConstCount: @error = 2 9, 9, 3 TVSourceCreatePlainExConstCount: @error = 2 9, 4, 4 TVSourceCreatePlainExConstCount: @error = 2 9, 5, 5 TVSourceCreatePlainExConstCount: @error = 2 9, 6, 6 TVSourceCreatePlainExConstCount: @error = 2 9, 7, 7 TVSourceCreatePlainExConstCount: @error = 2 9, 8, 8 TVSourceCreatePlainExConstCount: @error = 2 9, 9, 9 TVSourceCreatePlainExConstCount: @error = 2 9, 10, 10 $iLevels, $iItems0, $iMultiplier, $iCount = 10, 2, 2, 4447027 $iLevels, $iItems0, $iMultiplier, $iCount = 10, 4, 2, 8894054 TVSourceCreatePlainExConstCount: @error = 2 10, 6, 2 TVSourceCreatePlainExConstCount: @error = 2 10, 3, 3 TVSourceCreatePlainExConstCount: @error = 2 10, 4, 4 TVSourceCreatePlainExConstCount: @error = 2 10, 5, 5 TVSourceCreatePlainExConstCount: @error = 2 10, 6, 6 TVSourceCreatePlainExConstCount: @error = 2 10, 7, 7 TVSourceCreatePlainExConstCount: @error = 2 10, 8, 8 TVSourceCreatePlainExConstCount: @error = 2 10, 9, 9 TVSourceCreatePlainExConstCount: @error = 2 10, 10, 10 @error = 2 means that more than 10,000,000 items are generated. New 7z-file at bottom of first post. Edited January 8, 2023 by LarsJ argumentum 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...
LarsJ Posted January 15, 2023 Author Share Posted January 15, 2023 (edited) Compiled VB.NET code Since the source files for virtual treeviews are large files, it's advantageous and necessary to handle the files with compiled code. This post is about compiled VB.NET code. All code is located in the folder Examples\Part 2\2) Compiled VB.NET Code. Using VB.NET codeCompiled VB.NET methods can be executed in AutoIt scripts through the DotNetAll.au3 UDF. Here the VB.NET code is loaded with the function TVSourceCreateVbNetCodeObject(): ; Create $oVbNetCode object ; Executes treeview source file functions as compiled VB.NET code ; ; Error code in @error Return value ; 1 -> Failed to locate TVSourceFile.vb Success -> 1 or $oVbNetCode ; 2 -> Failed to create $oVbNetCode object Failure -> 0 ; Func TVSourceCreateVbNetCodeObject( _ $sVbNetCodePath = "" ) ; Relative path to VB.NET source code file ; VB.NET source code is saved in Includes\TVSourceFile.vb ; The path to set is the relative path from the running script to this file Local Static $bVbNetCodeObject = 0, $oNetCode, $oVbNetCode If Not $sVbNetCodePath And $bVbNetCodeObject Then Return $oVbNetCode ; Locate TVSourceFile.vb If Not FileExists( $sVbNetCodePath ) Then Return SetError( 1, 0, 0 ) ; Create $oVbNetCode object $oNetCode = DotNet_LoadVBcode( FileRead( $sVbNetCodePath ), "System.dll" ) $oVbNetCode = DotNet_CreateObject( $oNetCode, "TVSourceFile" ) If Not IsObj( $oVbNetCode ) Then Return SetError( 2, 0, 0 ) $bVbNetCodeObject = 1 Return 1 EndFunc The first function call is an initialization, where the path to the VB.NET code is specified as a parameter, and where $oVbNetCode is created and stored as a local static variable in the function. A lot of AutoIt code is executed to create the $oVbNetCode object. Therefore, it's performance-optimizing to create the object only once during an initialization. The $oVbNetCode object is created at the top of a script this way: If Not TVSourceCreateVbNetCodeObject( "..\Includes\TVSourceFile.vb" ) Then ConsoleWrite( "TVSourceCreateVbNetCodeObject: @error = " & @error & @CRLF ) Exit 1 EndIf ..\Includes\TVSourceFile.vb contains the VB.NET code. In subsequent function calls without a path parameter, the stored $oVbNetCode object is returned. TVSourceFile.au3 (Includes\TVSourceFile.au3) This is the updated function list at top of file: ; Functions ; ----------------------------------- ; TVSourceCreatePlain() Create random plain source file for non-virtual treeview ; TVSourceCreatePlainDbg() Create random plain source file for non-virtual treeview. Debug version. ; TVSourceCreatePlainEx() Based on recursive function with support for 100 levels ; TVSourceCreatePlainExVb() Based on recursive function with support for 100 levels. VB.NET code. ; TVSourceCreatePlainExDbg() Based on recursive function with support for 100 levels. Debug version. ; TVSourceCreatePlainExDbgVb() Based on recursive function with support for 100 levels. Debug version. VB.NET code. ; TVSourceCreatePlainExConst() Create constant plain source file for non-virtual treeview. Debug version. Constant source file. ; TVSourceCreatePlainExConstVb() Create constant plain source file for non-virtual treeview. Debug version. Constant source file. VB.NET code. ; TVSourceCreatePlainExConstCount() Count number of treeview items generated by TVSourceCreatePlainExConst/Vb() above ; TVSourceCreatePlainExConstCountVb() Count number of treeview items generated by TVSourceCreatePlainExConst/Vb() above. VB.NET code. ; TVSourceCreateVirtual() Create random source file for virtual treeview ; TVSourceCreateVirtualDbg() Create random source file for virtual treeview. Debug version. Contains code comments. <<<<<<<<<< ; ; TVSourceConvertPlainToVirtual() Convert plain source file for non-virtual treeview to source file for virtual treeview ; TVSourceConvertPlainToVirtualVb() Convert plain source file for non-virtual treeview to source file for virtual treeview. VB.NET code. ; TVSourceConvertVirtualToPlain() Convert source file for virtual treeview to plain source file for non-virtual treeview ; ; TVSourceDisplayPlain() Display non-virtual treeview from plain source file ; TVSourceDisplayVirtual() Display virtual treeview from source file TVSourceFile.vb (Includes\TVSourceFile.vb)TVSourceFile.vb contains all the VB.NET code. You may take a closer look at the code yourself if you are interested. These are a few general considerations. When the VB.NET code is executed, a syntax check comparable to Au3Check is performed. If the AutoIt script is executed in SciTE, the syntax errors are displayed in the console. A runtime error will usually appear like this in the console: TVSourceFile.au3 (1323) : ==> The requested action with this object has failed: Local $iRet = $oVbNetCode.TVSourceConvertPlainToVirtualVb( $iLevels, $sTVPlainSrc, $sTVVirtualSrc ) Local $iRet = $oVbNetCode^ ERROR Several VB.NET features are used in the code, e.g. Files, Arrays, Lists, Dictionary objects, Recursive functions and Regular expressions. Also note that AutoIt code can be translated relatively directly and easily into VB.NET code. Examples (Examples\5) TVSourceConvertPlainToVirtualVb.au3) The Examples\ folder contains an example for each of the 5 functions implemented in VB.NET code. Run the examples in SciTE with F5. Treeview source files are stored in the Sources\ top folder. This is a closer look at example 5) TVSourceConvertPlainToVirtualVb.au3: #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=Y Opt( "MustDeclareVars", 1 ) #include "..\Includes\TVSourceFile.au3" If Not TVSourceCreateVbNetCodeObject( "..\Includes\TVSourceFile.vb" ) Then ConsoleWrite( "TVSourceCreateVbNetCodeObject: @error = " & @error & @CRLF ) Exit 1 EndIf Example( 6, 16, 4, 104284 ) ; 104,284 treeview items ;Example( 5, 81, 9, 1012329 ) ; 1,012,329 treeview items Func Example( $iLevels, $iItems0, $iMultiplier, $iCount ) Local $sSources = "..\..\..\..\Sources\" & $iLevels & " levels, " & $iCount & " items, " ConsoleWrite( "TVSourceCreatePlainExConstVb( " & $sSources & "Plain, debug.txt" & " ) Creating..." & @CRLF ) If TVSourceCreatePlainExConstVb( $iLevels, $iItems0, $iMultiplier, $sSources & "Plain, debug.txt" ) Then ConsoleWrite( "TVSourceConvertPlainToVirtualVb( " & $sSources & "Plain, debug.txt" & " ) Converting..." & @CRLF ) If TVSourceConvertPlainToVirtualVb( $iLevels, $sSources & "Plain, debug.txt", $sSources & "Virtual, debug.txt" ) Then ConsoleWrite( "TVSourceDisplayVirtual( " & $sSources & "Virtual, debug.txt" & " ) Displaying..." & @CRLF ) If Not TVSourceDisplayVirtual( $sSources & "Virtual, debug.txt" ) Then _ Return ConsoleWrite( "TVSourceDisplayVirtual: @error = " & @error & @CRLF ) Else Return ConsoleWrite( "TVSourceConvertPlainToVirtualVb: @error = " & @error & @CRLF ) EndIf Else Return ConsoleWrite( "TVSourceCreatePlainExConstVb: @error = " & @error & @CRLF ) EndIf EndFunc Notice how TVSourceCreateVbNetCodeObject() is initialized in the top part of the code. TVSourceConvertPlainToVirtualVb() is called in the middle of the function: ; Convert plain source file for non-virtual treeview to source file for virtual treeview. VB.NET code. ; ; Error code in @error Return value ; 1 -> Invalid $iLevels value Success -> 1 ; 2 -> Plain source file doesn't exist Failure -> 0 ; 3 -> Invalid or empty $aSource array ; 4 -> Invalid source file item format ; 5 -> Too many treeview elements ; 6 -> Couldn't get $oVbNetCode ; ; Errors 3 - 5 comes from TVSourceConvertPlainToVirtualVb() in TVSourceFile.vb ; Func TVSourceConvertPlainToVirtualVb( _ $iLevels, _ ; Treeview levels, 2 <= $iLevels <= 100 $sTVPlainSrc, _ ; Name of plain treeview input source file $sTVVirtualSrc ) ; Name of virtual treeview output source file If Not ( 2 <= $iLevels And $iLevels <= 100 ) Then Return SetError( 1, 0, 0 ) If Not FileExists( $sTVPlainSrc ) Then Return SetError( 2, 0, 0 ) ; Get $oVbNetCode object to execute function as compiled VB.NET code Local $oVbNetCode = TVSourceCreateVbNetCodeObject() If Not IsObj( $oVbNetCode ) Then Return SetError( 6, 0, 0 ) ; Execute TVSourceConvertPlainToVirtualVb() as compiled VB.NET code Local $iRet = $oVbNetCode.TVSourceConvertPlainToVirtualVb( $iLevels, $sTVPlainSrc, $sTVVirtualSrc ) If $iRet < 0 Then Return SetError( -$iRet+2, 0, 0 ) Return 1 EndFunc Notice again how TVSourceCreateVbNetCodeObject() is now called without a parameter. Also note that the name of the VB.NET method is the same as the name of the AutoIt function. New 7z-file at bottom of first post. Edited January 15, 2023 by LarsJ argumentum 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...
LarsJ Posted February 11, 2023 Author Share Posted February 11, 2023 Virtual TreeView functions These are, for now, the last functions directly concentrated on handling TreeView source files. Some of the functions are also implemented in VB.NET code. All code located in Examples\Part 2\3) Virtual TreeView Functions. Run the examples in SciTE with F5. TVSourceFile.au3 (Includes\TVSourceFile.au3) This is the updated function list at top of file: ; Functions ; ------------------------------------- ; TVSourceCreateVbNetCodeObject() Create $oVbNetCode object to execute treeview source file functions as compiled VB.NET code ; ; TVSourceCreatePlain() Create random plain source file for non-virtual treeview ; TVSourceCreatePlainDbg() Create random plain source file for non-virtual treeview. Debug version. ; TVSourceCreatePlainEx() Based on recursive function with support for 100 levels ; TVSourceCreatePlainExVb() Based on recursive function with support for 100 levels. VB.NET code. ; TVSourceCreatePlainExDbg() Based on recursive function with support for 100 levels. Debug version. ; TVSourceCreatePlainExDbgVb() Based on recursive function with support for 100 levels. Debug version. VB.NET code. ; TVSourceCreatePlainExConst() Create constant plain source file for non-virtual treeview. Debug version. Constant source file. ; TVSourceCreatePlainExConstVb() Create constant plain source file for non-virtual treeview. Debug version. Constant source file. VB.NET code. ; TVSourceCreatePlainExConstCount() Count number of treeview items generated by TVSourceCreatePlainExConst/Vb() above ; TVSourceCreatePlainExConstCountVb() Count number of treeview items generated by TVSourceCreatePlainExConst/Vb() above. VB.NET code. ; TVSourceCreateVirtual() Create random source file for virtual treeview ; TVSourceCreateVirtualDbg() Create random source file for virtual treeview. Debug version. Contains code comments. <<<<<<<<<< ; ; TVSourceCountPlainLevels() Count number of levels in plain treeview source file ; TVSourceCountPlainLevelsVb() Count number of levels in plain treeview source file. VB.NET code. ; TVSourceCountSubtreeItems() Count number of subtree items in plain/virtual treeview source file ; TVSourceCountSubtreeItemsVb() Count number of subtree items in plain/virtual treeview source file. VB.NET code. ; ; TVSourceConvertPlainToVirtual() Convert plain source file for non-virtual treeview to source file for virtual treeview ; TVSourceConvertPlainToVirtualVb() Convert plain source file for non-virtual treeview to source file for virtual treeview. VB.NET code. ; TVSourceConvertVirtualToPlain() Convert source file for virtual treeview to plain source file for non-virtual treeview ; ; TVSourceExtractSubtreeFromPlain() Extract plain subtree source file from plain treeview source file ; TVSourceExtractSubtreeFromPlainVb() Extract plain subtree source file from plain treeview source file. VB.NET code. ; TVSourceExtractSubtreeFromVirtual() Extract plain subtree source file from virtual treeview source file ; TVSourceExtractSubtreeFromVirtualVb() Extract plain subtree source file from virtual treeview source file. VB.NET code. ; ; TVSourceGetParentsFromVirtual() Get parents from root to item in true virtual source file ; ; TVSourceDisplayPlain() Display non-virtual treeview from plain source file ; TVSourceDisplayVirtual() Display virtual treeview from source file The new functions are the Count and Extract functions and TVSourceGetParentsFromVirtual(). Optionally collapse the first root node in the CountSubtreeItems and plain Extract examples. Then item 3432 becomes visible, which is the start item in these examples. New 7z-file at bottom of first post. argumentum 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...
kut0 Posted February 16, 2023 Share Posted February 16, 2023 Thank you very much 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