Script using ListView, TreeView and 'Map()' function - troublesome bug.

Issue #63 closed
Winter Laite created an issue

ISSUE

description

An attempt was made to port the code at the only example on the TreeView docs page.

The test code in its present state shows the parent folder icon, then throws an unhandled exception. No files are shown.

There were two places where KeyView threw errors while adding code section by section. Although I cannot say this with certainty, it appears the errors in Keyview resulted from calling line 72 in the test code, i.e.

    ;SB.SetText(LV.GetCount() " files ", 1) ; Fails (index out of range)

where ‘TreeRoot’ in the code is set this way:

TreeRoot := A_MyDocuments "\Guitar" ; relatively sparsely populated folder to reduce load time

The attempted workaround, which at least allowed the code to start, is at line 71:

SB.SetText(ListViewGetContent("Count", LV, MyGui) " files", 1)

instead of the commented-out line 72, which is:

SB.SetText(LV.GetCount() " files ", 1) ; Fails (index out of range)
test code
; The following folder will be the root folder for the TreeView. Note that loading might take a long
; time if an entire drive such as C:\ is specified:
; [Smaller directory called to reduce load time.]
TreeRoot := A_MyDocuments "\Guitar"
TreeViewWidth := 280
ListViewWidth := A_ScreenWidth/2 - TreeViewWidth - 30

; Create the MyGui window and display the source directory (TreeRoot) in the title bar:
MyGui := Gui("+Resize", TreeRoot)  ; Allow the user to maximize or drag-resize the window.

; Create an ImageList and put some standard system icons into it:
ImageListID := IL_Create(5)
Loop 5 
    IL_Add(ImageListID, "shell32.dll", A_Index)
; Create a TreeView and a ListView side-by-side to behave like Windows Explorer:
TV := MyGui.Add("TreeView", "r20 w" TreeViewWidth " ImageList" ImageListID)
LV := MyGui.Add("ListView", "r20 w" ListViewWidth " yp x+10", ["Name","Modified"])

; Create a Status Bar to give info about the number of files and their total size:
SB := MyGui.Add("StatusBar")
SB.SetParts(60, 85)  ; Create three parts in the bar (the third part fills all the remaining width).

; Add folders and their subfolders to the tree. Display the status in case loading takes a long time:
M := Gui("ToolWindow -SysMenu Disabled AlwaysOnTop", "Loading the tree..."), M.Show("w200 h0")
DirList := AddSubFoldersToTree(TreeRoot, Map())
M.Hide()

; Call TV_ItemSelect whenever a new item is selected:
TV.OnEvent("ItemSelect", "TV_ItemSelect")

; Call Gui_Size whenever the window is resized:
; MyGui.OnEvent("Size", "Gui_Size")

; Set the ListView's column widths (this is optional):
Col2Width := 70  ; Narrow to reveal only the YYYYMMDD part.
LV.ModifyCol(1, ListViewWidth - Col2Width - 30)  ; Allows room for vertical scrollbar.
LV.ModifyCol(2, Col2Width)

; Display the window. The OS will notify the script whenever the user performs an eligible action:
MyGui.Show()

AddSubFoldersToTree(Folder, DirList, ParentItemID := 0)
{
    ; This function adds to the TreeView all subfolders in the specified folder
    ; and saves their paths associated with an ID into an object for later use.
    ; It also calls itself recursively to gather nested folders to any depth.
    Loop Files, Folder "\*.*", "D"  ; Retrieve all of Folder's sub-folders.
    {
        ItemID := TV.Add(A_LoopFileName, ParentItemID, "Icon4")
        DirList[ItemID] := A_LoopFilePath
        DirList := AddSubFoldersToTree(A_LoopFilePath, DirList, ItemID)
    }
    return DirList

}

TV_ItemSelect(thisCtrl, Item)  ; This function is called when a new item is selected.
{
    ; Put the files into the ListView:
    LV.Delete()  ; Clear all rows.
    LV.Opt("-Redraw")  ; Improve performance by disabling redrawing during load.
    TotalSize := 0  ; Init prior to loop below.
    Loop Files, DirList[Item] "\*.*"  ; For simplicity, omit folders so that only files are shown in the ListView.
    {
        LV.Add("", A_LoopFileName, A_LoopFileTimeModified)
        TotalSize += A_LoopFileSize
    }
    LV.Opt("+Redraw")

    ; Update the three parts of the status bar to show info about the currently selected folder:
    SB.SetText(ListViewGetContent("Count", LV, MyGui) " files", 1) ; should = below, but doesn't fail
    ;SB.SetText(LV.GetCount() " files ", 1) ; Fails (index out of range)
    SB.SetText(Round(TotalSize / 1024, 1) " KB", 2)
    SB.SetText(DirList[Item], 3)
}
error thrown

The test code fails with this error (truncated):

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.InvalidCastException: Unable to cast object of type 'System.IntPtr' to type 'System.IConvertible'.
   at System.Convert.ToInt32(Object value)
suspected cause

One of these functions (unable to determine which) appears to be returning a System.IntPtr, which Keysharp can’t cast to System.IConvertible.

Comments (6)

  1. Winter Laite reporter

    Update: One of the latest commits has changed the error message, perhaps making it easier to narrow down:

    ************** Exception Text **************
    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
     ---> Message: Key 1788461010208 was not present in the map.
    What: Keysharp.Core.Map.get_Item()
    

  2. Matt Feemster repo owner

    I’ve committed a fix, please test.

    -The parsing bug should be gone. It was fixed with my previous commit for chained method calls.

    -Fixed the bug which threw the map error.

    -Turning redraw on and off via Opt() was not properly working, but is fixed now.

  3. Winter Laite reporter

    Following the latest commits, no error is thrown for this test, but the output is not correct. In ‘A_MyDocuments’, which in my case is absurdly large, I get the result in the image.

  4. Log in to comment