1 (изменено: Bulef, 2024-03-09 11:28:47)

Тема: AHK v2: TreeView как альтернатива DirSelect

Здравствуйте. Захотелось создать кастомное окно по типу DirSelect. Сделал вот такое решение:

#Requires AutoHotkey v2.0

TreeView1 := []
TreeView1.Gui := Gui()
TreeView1.Gui.TreeView := TreeView1.Gui.Add("TreeView")
DrivesList := DriveGetList("FIXED")

; Парсит все диски
;Loop Parse DrivesList {
;	Loop Files A_LoopField ":\*", "DR" {

; Тестовый путь
{
	Loop Files "C:\Program Files\*", "DR" { ; Впишите тестовый путь
		TreeView1.HigherPropName := ""
		Loop Parse A_LoopFileFullPath, "\", "" {
			TreeViewName := A_LoopField
			PropName := A_LoopField
			PropName := StrReplace(PropName, " ", "_Space", 0)
			PropName := StrReplace(PropName, ".", "_Dot", 0)
			PropName := StrReplace(PropName, "``", "_Accent", 0)
			PropName := StrReplace(PropName, "`;", "_Semicolon", 0)
			PropName := StrReplace(PropName, "`:", "_Colon", 0)
			PropName := StrReplace(PropName, "`{", "_LeftCurlyBrace", 0)
			PropName := StrReplace(PropName, "`"", "_DoubleQuoteMark", 0)
			PropName := StrReplace(PropName, "`'", "_QuoteMark", 0)
			
			If (TreeView1.HigherPropName = "" AND !HasProp(TreeView1, PropName)) {
				TreeView1.%PropName% := []
				TreeView1.%PropName%.TreeViewProp := TreeView1.Gui.TreeView.Add(TreeViewName)
				TreeView1.HigherPropName := PropName
			}
			Else
			If (TreeView1.HigherPropName = "" AND HasProp(TreeView1, PropName))
				TreeView1.HigherPropName := PropName
			Else
			If (TreeView1.HigherPropName != "") {
				PropSource := TreeView1
				Loop Parse TreeView1.HigherPropName, ".", "" {
					TreePropName := A_LoopField
					PropSource := PropSource.%TreePropName%
				}
				
				If (!HasProp(PropSource, PropName)) {
					PropSource.%PropName% := []
					PropSource.%PropName%.TreeViewProp := TreeView1.Gui.TreeView.Add(TreeViewName, PropSource.TreeViewProp)
					TreeView1.HigherPropName := TreeView1.HigherPropName "." PropName
				}
				Else
				If (HasProp(PropSource, PropName))
					TreeView1.HigherPropName := TreeView1.HigherPropName "." PropName
			}
		}
	}
}

TreeView1.Gui.Show()

Проблема в том, что оно оказалось очень медленным и если парсить все диски, на каком-то этапе выдаёт ошибку. Причину ошибки я не смог найти.
Есть ли какие-то решения для TreeView, чтобы можно было быстро отрисовать окно, и если нет, подскажите, где искать ошибку?

2

Re: AHK v2: TreeView как альтернатива DirSelect

Как-то у вас больно мудрёно получилось, непонятно, чего хотели добиться. У меня ваш код сразу выдаёт ошибку.
По-моему, вы выбрали какой-то семантически неверный подход. Вы берёте массив TreeView1 := [], потом начинаете присваивать ему свойства: TreeView1.Gui := Gui(), TreeView1.%PropName% := [] ... Хотя массив и является объектом, и присваивание свойств не запрещено, он для этого совсем не предназначен. В массиве в качестве свойств должны быть только индексы.
Вот эта часть

			PropName := StrReplace(PropName, " ", "_Space", 0)
			PropName := StrReplace(PropName, ".", "_Dot", 0)
			PropName := StrReplace(PropName, "``", "_Accent", 0)
			PropName := StrReplace(PropName, "`;", "_Semicolon", 0)
			PropName := StrReplace(PropName, "`:", "_Colon", 0)
			PropName := StrReplace(PropName, "`{", "_LeftCurlyBrace", 0)
			PropName := StrReplace(PropName, "`"", "_DoubleQuoteMark", 0)
			PropName := StrReplace(PropName, "`'", "_QuoteMark", 0)

вообще непонятно для чего.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

3

Re: AHK v2: TreeView как альтернатива DirSelect

teadrinker
Спасибо за ответ.

У меня скрипт работает на одном диске, а на другом не хочет. Попробуйте протестировать на какой-нибудь папке содержащей внутри мало подпапок, желательно в корне диска.
Я самоучка, по этому делаю как научился. Честно говоря не вижу проблем в использовании массивов в качестве хранилищ собственности и вложенной собственности.

В указанной ниже части я избавляюсь от escape character`ов в названии, так как предполагал, что проблема может быть в названии папки.

По поводу ошибки. Есть предположение, что есть какой-то лимит уровня вложенной собственности и дальше него уже собственность не создаётся.

4

Re: AHK v2: TreeView как альтернатива DirSelect

Нет, у меня ошибка сразу же, сейчас не у компьютера, не могу показать скриншот.
Избавляться от каких-либо символов нет смысла, в качестве ключа можно использовать что угодно, даже объект.
Массив здесь абсолютно не подходит, как я сказал выше. Для подобных целей, когда нужно сохранять данные в виде ключ-значение, обычно используется Map().

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

5 (изменено: Bulef, 2024-03-09 11:25:53)

Re: AHK v2: TreeView как альтернатива DirSelect

Попробуйте вот этот вариант:

#Requires AutoHotkey v2.0

TreeView1 := []
TreeView1.Gui := Gui()
TreeView1.TreeView := TreeView1.Gui.Add("TreeView")
TreeView1.AttachmentsTree := Map()
DrivesList := DriveGetList("FIXED")

; Парсит все диски
;Loop Parse DrivesList {
;	Loop Files A_LoopField ":\*", "DR" {

; Тестовый путь
{
	Loop Files "C:\Program Files\*", "DR" { ; Впишите тестовый путь
		TreeView1.HigherAttachmentsNames := ""
		Loop Parse A_LoopFileFullPath, "\", "" {
			AttachmentName := A_LoopField
			
			If (TreeView1.HigherAttachmentsNames = "" AND !TreeView1.AttachmentsTree.Has(AttachmentName)) {
				TreeView1.AttachmentsTree[AttachmentName] := Map()
				TreeView1.AttachmentsTree[AttachmentName].TreeViewProp := TreeView1.TreeView.Add(AttachmentName)
				TreeView1.HigherAttachmentsNames := AttachmentName
			}
			Else
			If (TreeView1.HigherAttachmentsNames = "" AND TreeView1.AttachmentsTree.Has(AttachmentName))
				TreeView1.HigherAttachmentsNames := AttachmentName
			Else
			If (TreeView1.HigherAttachmentsNames != "") {
				AttachmentsSource := TreeView1.AttachmentsTree
				Loop Parse TreeView1.HigherAttachmentsNames, "|", "" {
					TreeAttachmentName := A_LoopField
					AttachmentsSource := AttachmentsSource[TreeAttachmentName]
				}
				
				If (!AttachmentsSource.Has(AttachmentName)) {
					AttachmentsSource[AttachmentName] := Map()
					AttachmentsSource[AttachmentName].TreeViewProp := TreeView1.TreeView.Add(AttachmentName, AttachmentsSource.TreeViewProp)
					TreeView1.HigherAttachmentsNames := TreeView1.HigherAttachmentsNames "|" AttachmentName
				}
				Else
				If (AttachmentsSource.Has(AttachmentName))
					TreeView1.HigherAttachmentsNames := TreeView1.HigherAttachmentsNames "|" AttachmentName
			}
		}
	}
}

TreeView1.Gui.Show()

У меня всё заработало без ошибок даже если поставить парситься все диски. Но так или иначе, это нецелесообразно, так как процесс построения контрола занимает слишком много времени. Не знаю пока что с этим сделать. Видимо придётся отказаться от идеи и использовать DirSelect.

А можно ли изменить цвет фона и текста в DirSelect? Это возможно?


Обновлено:
Я сделал быстрый вариант TreeView. Пока черновой вариант. Итемы в TreeView будут прогружаться по мере разворачивания директорий, а не сразу всё древо, как в варианте выше. Допишу класс и выложу как сделаю.

6

Re: AHK v2: TreeView как альтернатива DirSelect

Bulef пишет:

А можно ли изменить цвет фона и текста в DirSelect?

Может, как-то и можно, но вряд ли просто. Это системное окно, а не окно, которое создаёт скрипт.

Bulef пишет:

прогружаться по мере разворачивания директорий

Вот это верный подход.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

7

Re: AHK v2: TreeView как альтернатива DirSelect

Вот класс:

#Requires AutoHotkey v2.0

Gui1 := Gui()
Settings := Map()
Settings["TreeViewOptions"] := "r15"
TreeView1 := TreeViewDirSelect(Gui1, "C:\Program Files", Settings)
Gui1.Show()
Loop {
	Sleep 5000
	ItemID := TreeView1.TreeView.GetSelection()
	Path := TreeView1.IDToPath[ItemID]
	MsgBox Path
}


Class TreeViewDirSelect {
	/*
	By Bulef
	Версия 0.01
	---------------------------------------
	Тестовые настройки:
Gui1 := Gui()
TreeView1 := TreeViewDirSelect(Gui1, "C:\Program Files")
Gui1.Show()
	---------------------------------------
	В первой опции (Gui) необходимо дать ссылку на ваш Gui, чтобы разместить TreeView в нём. Эта настройка обязательная.
	Вторая опция (DefaultDir) позволяет выбрать директорию по умолчанию, из которой будет происходить открытие папок. Вы можете указать эту настройку пустой (""), чтобы отобразить ваши диски как изначальную директорию.
	Третья опция (Settings) позволяет внести дополнительные настройки при создании TreeView. Для этого создайте карту:
Settings := Map()
	И добавьте нужную опцию.
Settings["TreeViewOptions"] := "r15"
	Позволит добавить опции AHK Gui при создани TreeView (Искать в руководстве AHK по Gui Object).
Settings["ShowHiddenFolders"] := True
	Позволит показать скрытые папки.
	После чего добавьте опцию Settings при создании класса:
TreeView1 := TreeViewDirSelect(Gui1, "C:\Program Files", Settings)
	---------------------------------------
	Элемент TreeView будет находиться в собственности "TreeView" родительского объекта ("TreeView1"), то есть в "TreeView1.TreeView" как в примере.
	---------------------------------------
	Для того, чтобы получить, к примеру путь к выбранной в TreeView папке, необходимо получить ID элемента и найти его в карте TreeView1.IDToPath.
	Для этого вызываем функцию GetSelection в TreeView.
ItemID := TreeView1.TreeView.GetSelection()
	После чего ищем её в TreeView1.IDToPath
Path := TreeView1.IDToPath[ItemID]
	Также возможно найти ItemID имея путь в TreeView1.PathToID, если он уже отрисован.
ItemID := TreeView1.PathToID[Path]
	Остальные возможные варианты взаимодействия с TreeView ищите в руководстве AHK по TreeView.
	*/
	
	__New(Gui, DefaultDir := "", Settings := "") {
		If (IsObject(Settings)) {
			If (Settings.Has("TreeViewOptions"))
				This.TreeViewOptions := Settings["TreeViewOptions"]
			Else
				This.TreeViewOptions := ""
			If (Settings.Has("ShowHiddenFolders"))
				This.ShowHiddenFolders := Settings["ShowHiddenFolders"]
			Else
				This.ShowHiddenFolders := False
		}
		Else
		If (!IsObject(Settings)) {
			This.TreeViewOptions := ""
			This.ShowHiddenFolders := False
		}
		
		This.TreeView := Gui.Add("TreeView", This.TreeViewOptions)
		This.TreeView.OnEvent("ItemExpand", (GuiCtrlObj, Item, Expanded) => This.TreeViewItemExpand(GuiCtrlObj, Item, Expanded))
		
		This.DefaultDir := DefaultDir
		This.DrivesList := DriveGetList("FIXED")
		
		This.PathToID := Map()
		This.IDToPath := Map()
		
		If (This.DefaultDir = "") {
			Loop Parse This.DrivesList
				This.AddItem(A_LoopField ":")
		}
		Else
		If (This.DefaultDir != "") {
			This.AddItem(This.DefaultDir)
			Loop Files This.DefaultDir "\*", "D"
				This.AddItem(A_LoopFileFullPath)
		}
	}
	
	AddItem(Path) {
		Loop Files Path "\*", "D" {
			If (!This.ShowHiddenFolders AND InStr(A_LoopFileAttrib, "H", 0))
				Continue
			HigherDirPath := ""
			FullDirPath := ""
			TrimmedPath := This.DefaultDir
			Loop Parse A_LoopFileFullPath, "\", "" {
				DirName := A_LoopField
				If (FullDirPath = "")
					FullDirPath := DirName
				Else
				If (FullDirPath != "")
					FullDirPath := FullDirPath "\" DirName
				If (InStr(TrimmedPath, DirName, 1, 1, ) = 1) {
					If (TrimmedPath = DirName)
						TrimmedPath := ""
					Else
						TrimmedPath := SubStr(TrimmedPath, StrLen(DirName "\")+1, )
					Continue
				}
				If (HigherDirPath = "")
					DirPath := DirName
				Else
				If (HigherDirPath != "")
					DirPath := HigherDirPath "\" DirName
				DriveName := ""
				If (A_Index = 1 AND InStr(DirName, ":", , -1, ))
					DriveName := DriveGetLabel(DirName) " (" DirName ")"
				
				
				If (HigherDirPath = "" AND !This.PathToID.Has(DirPath)) {
					If (DriveName = "")
						This.PathToID[DirPath] := This.TreeView.Add(DirName)
					Else
					If (DriveName != "")
						This.PathToID[DirPath] := This.TreeView.Add(DriveName)
					This.IDToPath[This.PathToID[DirPath]] := FullDirPath
					HigherDirPath := DirPath
				}
				Else
				If (HigherDirPath != "" AND !This.PathToID.Has(DirPath)) {
					HigherDirPathID := This.PathToID[HigherDirPath]
					This.PathToID[DirPath] := This.TreeView.Add(DirName, HigherDirPathID)
					This.IDToPath[This.PathToID[DirPath]] := FullDirPath
					HigherDirPath := DirPath
				}
				Else
				If (This.PathToID.Has(DirPath))
					HigherDirPath := DirPath
			}
		}
	}
	
	TreeViewItemExpand(GuiCtrlObj, Item, Expanded) {
		If (!Expanded)
			Return
		Path := This.IDToPath[Item]
		Loop Files Path "\*", "D"
			This.AddItem(A_LoopFileFullPath)
	}
}

Работает быстро. То что я и хотел. Может кому ещё пригодится.

8

Re: AHK v2: TreeView как альтернатива DirSelect

В целом всё ок, но есть небольшой недостаток. У меня на компьютере с HDD после раскрытия узлов не всегда успевают прогружаться раскрывающиеся вложенные узлы. По идее нужно изначально загрузить несколько уровней сразу, а при раскрытии загружать уже более глубокие уровни. Как-то так:

#Requires AutoHotkey v2

paths := Map()
wnd := Gui('Resize')
wnd.OnEvent('Close', (*) => ExitApp())
wnd.OnEvent('Size', (g, mm, w, h) => (
    selectedPath.Move(,, w - g.MarginX * 2),
    tree.Move(,, w - g.MarginX * 2, h - g.MarginY * 3 - 20)
))
selectedPath := wnd.AddEdit('w400 h20')
tree := wnd.AddTreeView('wp h300')
tree.OnEvent('ItemExpand', OnExpand)
tree.OnEvent('ItemSelect', (ctrl, item) => selectedPath.Value := RegExReplace(paths[item], '\\$'))
root := tree.Add('My Computer',, 'Expand')
paths[root] := 'My Computer'

; добавляем сначала только три уровня
loop parse DriveGetList('FIXED') {
    node := tree.Add(drive := A_LoopField . ':', root)
    paths[node] := drive
    loop files drive . '\*', 'D' {
        childNode := tree.Add(A_LoopFileName, node)
        paths[childNode] := A_LoopFilePath
        loop files A_LoopFilePath . '\*', 'D' {
            paths[tree.Add(A_LoopFileName, childNode)] := A_LoopFilePath
        }
    }
}
wnd.Show()

; остальные уровни добавляем при раскрытии узлов дерева
OnExpand(tree, item, expanded) {
    if !expanded || paths[item] ~= '\\$' {
        return
    }
    ; отмечаем узел, с которым будем работать, добавляя слеш в конец пути
    ; чтобы не добавлять дочерние узлы повторно
    paths[item] .= '\'
    CreateSubTree(tree.GetChild(item), 0)

    CreateSubTree(item, level) {
        level++
        Loop {
            if level < 3 && next := tree.GetChild(item) {
                CreateSubTree(next, level)
            } else {
                loop files paths[item] . '\*', 'D' {
                    paths[tree.Add(A_LoopFileName, item)] := A_LoopFilePath
                }
            }
        } until !item := tree.GetNext(item)
    }
}

Особо не тестировал, может, тут не всё идеально.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

9 (изменено: Bulef, 2024-03-22 18:09:37)

Re: AHK v2: TreeView как альтернатива DirSelect

teadrinker
Подредактировал свою версию с учётом этой проблемы. У меня это практически не ощущается, по этому полноценно протестировать я не могу.
Вот новая версия класса:

#Requires AutoHotkey v2

Gui1 := Gui()
Gui1.OnEvent('Close', (*) => ExitApp())
DefaultDir := "C:\Program Files"
Text1 := Gui1.Add("Text", "", "DefaultDir:")
Edit1 := Gui1.Add("Edit", "W250 X" Gui1.MarginY " XM", DefaultDir)
Button1 := Gui1.Add("Button", "X" Gui1.MarginY " XM", "Change")
Button1.OnEvent('Click', ChangeDefaultDir)
Text2 := Gui1.Add("Text", "X" Gui1.MarginY " XM", "Selected Item:")
Edit2 := Gui1.Add("Edit", "W250 X" Gui1.MarginY " XM")

Settings := Map()
Settings["TreeViewOptions"] := "R15 W250 X" Gui1.MarginX
TreeView1 := TreeViewDirSelect(Gui1, DefaultDir, Settings)
TreeView1.TreeView.OnEvent('ItemSelect', (GuiCtrlObj, Item) => ItemSelect(GuiCtrlObj, Item))
Gui1.Show()

ItemSelect(GuiCtrlObj, Item) {
	If (TreeView1.IDToPath.Has(Item))
		Edit2.Text := TreeView1.IDToPath[Item]
}

ChangeDefaultDir(Button, Info) {
	Gui1.Submit(0)
	DefaultDir := Edit1.Text
	TreeView1.TreeViewOperations("TreeViewDirSelectRecreate", Gui1, DefaultDir)
}


Class TreeViewDirSelect {
	/*
	By Bulef
	Версия 0.02
	---------------------------------------
	Тестовые настройки:
Gui1 := Gui()
TreeView1 := TreeViewDirSelect(Gui1, "C:\Program Files")
Gui1.Show()
	---------------------------------------
	В первой опции (Gui) необходимо дать ссылку на ваш Gui, чтобы разместить TreeView в нём. Эта настройка обязательная.
	Вторая опция (DefaultDir) позволяет выбрать директорию по умолчанию, из которой будет происходить открытие папок. Вы можете указать эту настройку пустой (""), чтобы отобразить ваши диски как изначальную директорию.
	Третья опция (Settings) позволяет внести дополнительные настройки при создании TreeView. Для этого создайте карту:
Settings := Map()
	И добавьте нужную опцию.
Settings["TreeViewOptions"] := "R15"
	Позволит добавить опции AHK Gui при создани TreeView (Искать в руководстве AHK по Gui Object).
Settings["ShowHiddenFolders"] := True
	Позволит показать скрытые папки. Принимает значение либо True, либо False.
	После чего добавьте опцию Settings при создании класса:
TreeView1 := TreeViewDirSelect(Gui1, "C:\Program Files", Settings)
	---------------------------------------
	Элемент TreeView будет находиться в собственности "TreeView" родительского объекта ("TreeView1"), то есть в "TreeView1.TreeView" как в примере.
	---------------------------------------
	Также возможно пересоздать TreeView используя внутреннюю функцию "TreeViewOperations".
	Для этого вызовите её из родительского объекта и добавьте первой опцию "TreeViewDirSelectRecreate", вставив остальные опции после неё:
TreeView1.TreeViewOperations("TreeViewDirSelectRecreate", Gui1, "C:\Program Files")
	Также существует такая опция:
TreeView1.TreeViewOperations("TreeViewDirSelectCreate", Gui1, "C:\Program Files")
	Она создаст TreeView заново. Если не знаете точно, что это вам требуется, не используйте её.
	---------------------------------------
	Для того, чтобы получить, к примеру путь к выбранной в TreeView папке, необходимо получить ID элемента и найти его в карте TreeView1.IDToPath.
	Для этого вызываем функцию GetSelection в TreeView.
ItemID := TreeView1.TreeView.GetSelection()
	После чего ищем её в TreeView1.IDToPath
Path := TreeView1.IDToPath[ItemID]
	Также возможно найти ItemID имея путь в TreeView1.PathToID, если он уже отрисован.
ItemID := TreeView1.PathToID[Path]
	Остальные возможные варианты взаимодействия с TreeView ищите в руководстве AHK по TreeView.
	*/
	
	__New(Gui, DefaultDir := "", Settings := "") {
		This.TreeViewOperations("TreeViewDirSelectCreate", Gui, DefaultDir, Settings)
	}
	
	TreeViewOperations(TreeViewDirSelectOption, Gui, DefaultDir := "", Settings := "") {
		If (TreeViewDirSelectOption = "TreeViewDirSelectCreate") {
			If (IsObject(Settings)) {
				If (Settings.Has("TreeViewOptions"))
					This.TreeViewOptions := Settings["TreeViewOptions"]
				Else
					This.TreeViewOptions := ""
				If (Settings.Has("ShowHiddenFolders"))
					This.ShowHiddenFolders := Settings["ShowHiddenFolders"]
				Else
					This.ShowHiddenFolders := False
			}
			Else
			If (!IsObject(Settings)) {
				This.TreeViewOptions := ""
				This.ShowHiddenFolders := False
			}
		}
		Else
		If (TreeViewDirSelectOption = "TreeViewDirSelectRecreate") {
			If (IsObject(Settings)) {
				If (Settings.Has("TreeViewOptions"))
					This.TreeViewOptions := Settings["TreeViewOptions"]
				If (Settings.Has("ShowHiddenFolders"))
					This.ShowHiddenFolders := Settings["ShowHiddenFolders"]
			}
		}
		
		If (TreeViewDirSelectOption = "TreeViewDirSelectCreate") {
			This.TreeView := Gui.Add("TreeView", This.TreeViewOptions)
			This.TreeView.OnEvent("ItemExpand", (GuiCtrlObj, Item, Expanded) => This.TreeViewItemExpand(GuiCtrlObj, Item, Expanded))
		}
		Else
		If (TreeViewDirSelectOption = "TreeViewDirSelectRecreate") {
			This.TreeView.Opt(This.TreeViewOptions)
			This.TreeView.Delete()
		}
		
		This.DefaultDir := DefaultDir
		This.DrivesList := DriveGetList("FIXED")
		
		This.PathToID := Map()
		This.IDToPath := Map()
		This.IDToDefaultDir := Map()
		
		
		This.PreLoadLevels(This.DefaultDir, This.DefaultDir, 2)
		
		This.TreeView.Redraw()
	}
	
	PreLoadLevels(Path, DefaultDir, Level) {
		PathArray := []
		If (Path = "" AND DefaultDir = "") {
			Loop Parse This.DrivesList {
				DriveName := A_LoopField ":"
				PathArray.Push(DriveName)
				If (!This.PathToID.Has(DriveName)) {
					DriveFullName := DriveGetLabel(DriveName) " (" DriveName ")"
					DirID := This.TreeView.Add(DriveFullName)
					This.PathToID[DriveName] := DirID
					This.IDToPath[DirID] := DriveName
					This.IDToDefaultDir[DirID] := ""
				}
			}
		}
		Else
			PathArray.Push(Path)
		
		If (IsInteger(Level) AND Level >= 1 OR InStr(Level, "=", , 1, ) = 1 AND SubStr(Level, 2, ) >= 1) {
			For PathID, Path In PathArray {
				Path1 := Path
				If (IsInteger(Level) AND Level >= 1 OR Level = "=1")
					This.AddItem(Path1, DefaultDir)
				
				If (IsInteger(Level) AND Level >= 2 OR InStr(Level, "=", , 1, ) = 1 AND SubStr(Level, 2, ) >= 2) {
					Loop Files Path1 "\*", "D" {
						Path2 := A_LoopFileFullPath
						If (IsInteger(Level) AND Level >= 2 OR Level = "=2")
							This.AddItem(Path2, DefaultDir)
						
						If (IsInteger(Level) AND Level >= 3 OR InStr(Level, "=", , 1, ) = 1 AND SubStr(Level, 2, ) >= 3) {
							Loop Files Path2 "\*", "D" {
								Path3 := A_LoopFileFullPath
								If (IsInteger(Level) AND Level >= 3 OR Level = "=3")
									This.AddItem(Path3, DefaultDir)
							}
						}
					}
				}
			}
		}
	}
	
	AddItem(Path, DefaultDir) {
		Loop Files Path "\*", "D" {
			If (!This.ShowHiddenFolders AND InStr(A_LoopFileAttrib, "H", 0))
				Continue
			HigherDirPath := ""
			FullDirPath := A_LoopFileFullPath
			TrimmedPath := FullDirPath
			If (DefaultDir != "" AND InStr(FullDirPath, DefaultDir, 1, 1, ) = 1)
				TrimmedPath := SubStr(FullDirPath, StrLen(DefaultDir "\")+1, )
			Loop Parse TrimmedPath, "\", "" {
				DirName := A_LoopField
				If (HigherDirPath = "")
					DirPath := DirName
				Else
				If (HigherDirPath != "")
					DirPath := HigherDirPath "\" DirName
				
				If (!This.PathToID.Has(DirPath)) {
					If (HigherDirPath = "")
						DirID := This.TreeView.Add(DirName)
					Else
					If (HigherDirPath != "") {
						HigherDirPathID := This.PathToID[HigherDirPath]
						DirID := This.TreeView.Add(DirName, HigherDirPathID)
					}
					This.PathToID[DirPath] := DirID
					This.IDToPath[DirID] := FullDirPath
					This.IDToDefaultDir[DirID] := DefaultDir
					HigherDirPath := DirPath
				}
				Else
				If (This.PathToID.Has(DirPath))
					HigherDirPath := DirPath
			}
		}
	}
	
	TreeViewItemExpand(GuiCtrlObj, Item, Expanded) {
		If (!Expanded)
			Return
		Path := This.IDToPath[Item]
		DefaultDir := This.IDToDefaultDir[Item]
		This.PreLoadLevels(Path, DefaultDir, "=3")
	}
}

Различие между нашими вариантами только в том, что в моём можно изменить директорию по умолчанию, из которой будут открываться папки. В остальном можно использовать любой из вариантов.


Обновлено:
Возникала ошибка если очень быстро обновлять директорию по умолчанию. Я это исправил. Возможно буду периодически ещё вносить корректировки.

10

Re: AHK v2: TreeView как альтернатива DirSelect

Да, теперь всё вроде в порядке.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder