如何在AutoIt的ListView中检查项是否存在,避免重复添加拖拽文件?
AutoIT拖拽文件到ListView避免重复添加的解决方案
问题背景
现有AutoIT程序支持将Windows文件拖拽到由GUICtrlCreateListView()创建的列表中,但存在重复添加文件的问题。同时ControlListView()函数仅支持32位系统,在64位环境下无法正常工作,需要替代方案。
原始代码如下:
GuiCreate('Drag and Drop', 530, 320, @DesktopWidth / 2 - 192, @DesktopHeight / 2 - 235, -1, $WS_EX_ACCEPTFILES) GUICtrlCreateLabel('File:', 20, 30) Local $dropControl = GUICtrlCreateInput('', 80, 30, 400, 24, -1, $WS_EX_STATICEDGE) Local $dropList = GUICtrlCreateListView('File', 80, 80, 400, 200) ;, -1, $WS_EX_STATICEDGE) GUICtrlSetState ($dropControl, $GUI_DROPACCEPTED) GUICtrlSetTip ($dropControl, 'Drag File here …') GUISetOnEvent($GUI_EVENT_DROPPED, 'doDrop') Func doDrop() $dropFiles = GUICtrlRead(@GUI_DropId) Local $files = StringSplit($dropFiles, '|') For $i=1 to $files[0] $file = $files[$i] ; How do I test wheter the item already exists? Local $item = GUICtrlCreateListViewItem($file, $dropList) GUICtrlSetData($item, $file) Next GUICtrlSetData($dropControl, '') EndFunc
解决方案
方案1:遍历ListView现有项检查重复(无需额外缓存)
通过GUICtrlRead()结合循环遍历ListView的所有项,对比当前文件路径(忽略Windows路径大小写),判断是否已存在。
修改后的完整代码:
GuiCreate('Drag and Drop', 530, 320, @DesktopWidth / 2 - 192, @DesktopHeight / 2 - 235, -1, $WS_EX_ACCEPTFILES) GUICtrlCreateLabel('File:', 20, 30) Local $dropControl = GUICtrlCreateInput('', 80, 30, 400, 24, -1, $WS_EX_STATICEDGE) Local $dropList = GUICtrlCreateListView('File', 80, 80, 400, 200) GUICtrlSetState ($dropControl, $GUI_DROPACCEPTED) GUICtrlSetTip ($dropControl, 'Drag File here …') GUISetOnEvent($GUI_EVENT_DROPPED, 'doDrop') GUISetOnEvent($GUI_EVENT_CLOSE, '_Exit') Func doDrop() $dropFiles = GUICtrlRead(@GUI_DropId) Local $files = StringSplit($dropFiles, '|') For $i=1 to $files[0] $file = $files[$i] ; 检查文件是否已在列表中 If Not _IsFileInListView($dropList, $file) Then Local $item = GUICtrlCreateListViewItem($file, $dropList) GUICtrlSetData($item, $file) EndIf Next GUICtrlSetData($dropControl, '') EndFunc ; 自定义检查函数:判断文件是否已存在于ListView Func _IsFileInListView($hListView, $sFilePath) Local $iIndex = 0 While True Local $sItemText = GUICtrlRead($hListView, $GUI_INDEX, $iIndex) ; 遍历到空项说明已检查完所有项 If $sItemText = "" Then ExitLoop ; 忽略大小写对比路径(Windows路径不区分大小写) If StringCompare($sItemText, $sFilePath, 1) = 0 Then Return True EndIf $iIndex += 1 WEnd Return False EndFunc Func _Exit() Exit EndFunc GUISetState(@SW_SHOW) While 1 Sleep(100) WEnd
方案2:维护数组缓存已添加文件(效率更高)
当ListView项较多时,遍历会影响性能,可维护一个全局数组记录已添加的文件路径,每次添加前先检查数组:
修改后的核心代码:
; 全局数组,用于缓存已添加的文件,[0]为元素数量 Global $aAddedFiles[1] = [0] Func doDrop() $dropFiles = GUICtrlRead(@GUI_DropId) Local $files = StringSplit($dropFiles, '|') For $i=1 to $files[0] $file = $files[$i] ; 检查数组中是否已存在该文件 Local $bExists = False For $j=1 to $aAddedFiles[0] If StringCompare($aAddedFiles[$j], $file, 1) = 0 Then $bExists = True Break EndIf Next If Not $bExists Then ; 添加到ListView Local $item = GUICtrlCreateListViewItem($file, $dropList) GUICtrlSetData($item, $file) ; 更新缓存数组 $aAddedFiles[0] += 1 ReDim $aAddedFiles[$aAddedFiles[0]+1] $aAddedFiles[$aAddedFiles[0]] = $file EndIf Next GUICtrlSetData($dropControl, '') EndFunc
说明
- 两种方案均无需依赖
ControlListView(),完全兼容64位系统 - 使用
StringCompare(..., 1)忽略大小写,符合Windows文件系统的路径规则 - 方案2适合列表项较多的场景,避免重复遍历ListView带来的性能损耗
内容的提问来源于stack exchange,提问作者Manngo
相关产品推荐
相关产品推荐

