Что нового

TVExplorer UDF - Создание дерева папок и файлов

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
AutoIt: 3.3.8.1
Версия: 1.3

Категория: Элементы GUI

Описание: Данная библиотека является логическим продолжением этой темы и предназначена для создания дерева папок и файлов (TreeView) и обеспечения взаимодействия с ним. Создается TreeView Explorer всего одной фунуцией, а для регистрации необходимых событий используется пользовательская callback функция, в которую TreeView Explorer посылает соответствующие сообщения (аналогично WM-функциям). Как все это работает, наглядно показано в нижеследующем примере. TreeView Explorer может работать как в "OnEvent", так и в "Loop" режимах. В случае последнего, необходимо будет вместо функции GUIGetMsg() использовать _GUICtrlTVExplorer_GetMsg(), которая с точки зрения пользователя ничем не отличается от первой. UDF на данный момент имеет статус Beta, поэтому, просьба ко всем заинтересованным пользователям нашего форума хорошенько потестить библиотеку и отписаться в этой ветке с пожеланиями и багами. И еще, TVExplorer.au3 требует наличия WinAPIEx.au3 версии 3.2 и выше. Если у вас его нет (а у вас его точно нет), то временно используйте дополнение к версии 3.1 (файл [email protected] в архиве). И последнее, на данный момент библиотека имеет ряд следующих ограничений:

  • Одновременно можно создать только один элемент TreeView Explorer.
  • Могут быть существенные задержки, если в папках присутствует очень большое количество файлов/подпапок.
  • Невозможно заранее открыть произвольную папку в пределах корневой папки.
  • Не реализованы все возможности алгоритма (использованы не все $TV_FLAG_... флаги).
  • Регистрация ограниченного числа событий ($TV_NOTIFY_...).

Файл(ы): TVExplorer.zip
Пример:

Код:
#Include <GUIConstantsEx.au3>
#Include <GUITreeView.au3>
#Include <TVExplorer.au3>
#Include <TreeViewConstants.au3>
#Include <WindowsConstants.au3>
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global $hForm, $hTV[3], $Input[3], $hFocus = 0, $Dummy, $Path, $Style

If Not _WinAPI_DwmIsCompositionEnabled() Then
	$Style = $WS_EX_COMPOSITED
Else
	$Style = -1
EndIf
$hForm = GUICreate('TVExplorer UDF Example', 700, 736, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX), $Style)
GUISetIcon(@WindowsDir & '\explorer.exe')
$Input[0] = GUICtrlCreateInput('', 20, 20, 320, 19)
GUICtrlSetState(-1, $GUI_DISABLE)
$hTV[0] = _GUICtrlTVExplorer_Create(@ProgramFilesDir, 20, 48, 320, 310, -1, $WS_EX_CLIENTEDGE, -1, '_TVEvent')
$Input[1] = GUICtrlCreateInput('', 360, 20, 320, 19)
GUICtrlSetState(-1, $GUI_DISABLE)
$hTV[1] = _GUICtrlTVExplorer_Create(@UserProfileDir, 360, 48, 320, 310, -1, $WS_EX_CLIENTEDGE, -1, '_TVEvent')
$Input[2] = GUICtrlCreateInput('', 20, 378, 660, 19)
GUICtrlSetState(-1, $GUI_DISABLE)
$hTV[2] = _GUICtrlTVExplorer_Create('', 20, 406, 660, 310, -1, $WS_EX_CLIENTEDGE, -1, '_TVEvent')
For $i = 0 To 2
	_TVSetPath($Input[$i], _GUICtrlTVExplorer_GetSelected($hTV[$i]))
	_GUICtrlTVExplorer_SetExplorerStyle($hTV[$i])
Next
$Dummy = GUICtrlCreateDummy()
GUIRegisterMsg($WM_GETMINMAXINFO, 'WM_GETMINMAXINFO')
GUIRegisterMsg($WM_SIZE, 'WM_SIZE')
HotKeySet('{F5}', '_TVRefresh')
GUISetState()

_GUICtrlTVExplorer_Expand($hTV[0], @ProgramFilesDir & '\AutoIt3')
_GUICtrlTVExplorer_Expand($hTV[1])

While 1
	Switch _GUICtrlTVExplorer_GetMsg()
		Case $GUI_EVENT_CLOSE
			GUIDelete()
			_GUICtrlTVExplorer_DestroyAll()
			Exit
		Case $Dummy
			$Path = _GUICtrlTVExplorer_GetSelected($hFocus)
			_GUICtrlTVExplorer_AttachFolder($hFocus)
			_GUICtrlTVExplorer_Expand($hFocus, $Path, 0)
			$hFocus = 0
	EndSwitch
WEnd

Func _TVEvent($hWnd, $iMsg, $sPath, $hItem)
	Switch $iMsg
		Case $TV_NOTIFY_BEGINUPDATE
			GUISetCursor(1, 1)
		Case $TV_NOTIFY_ENDUPDATE
			GUISetCursor(2)
		Case $TV_NOTIFY_SELCHANGED
			For $i = 0 To 2
				If $hTV[$i] = $hWnd Then
					_TVSetPath($Input[$i], $sPath)
					ExitLoop
				EndIf
			Next
		Case $TV_NOTIFY_DBLCLK
			; Nothing
		Case $TV_NOTIFY_RCLICK
			; Nothing
		Case $TV_NOTIFY_DELETINGITEM
			; Nothing
		Case $TV_NOTIFY_DISKMOUNTED
			; Nothing
		Case $TV_NOTIFY_DISKUNMOUNTED
			; Nothing
	EndSwitch
EndFunc   ;==>_TVEvent

Func _TVSetPath($iInput, $sPath)

	Local $Text = _WinAPI_PathCompactPath(GUICtrlGetHandle($iInput), $sPath, -2)

	If GUICtrlRead($iInput) <> $Text Then
		GUICtrlSetData($iInput, $Text)
	EndIf
EndFunc   ;==>_TVSetPath

Func _TVRefresh()

	Local $hWnd = _WinAPI_GetFocus()

	For $i = 0 To 2
		If $hTV[$i] = $hWnd Then
			If Not $hFocus Then
				$hFocus = $hWnd
				GUICtrlSendToDummy($Dummy)
			EndIf
			Return
		EndIf
	Next
	HotKeySet('{F5}')
	Send('{F5}')
	HotKeySet('{F5}', '_TVRefresh')
EndFunc   ;==>_TVRefresh

Func WM_GETMINMAXINFO($hWnd, $iMsg, $wParam, $lParam)

	Local $tMMI = DllStructCreate('long Reserved[2];long MaxSize[2];long MaxPosition[2];long MinTrackSize[2];long MaxTrackSize[2]', $lParam)

	Switch $hWnd
		Case $hForm
			DllStructSetData($tMMI, 'MinTrackSize', 428, 1)
			DllStructSetData($tMMI, 'MinTrackSize', 450, 2)
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_GETMINMAXINFO

Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam)

	Local $WC, $HC, $WT, $HT

	Switch $hWnd
		Case $hForm
			$WC = _WinAPI_LoWord($lParam)
			$HC = _WinAPI_HiWord($lParam)
			$WT = Floor(($WC - 60) / 2)
			$HT = Floor(($HC - 116) / 2)
			GUICtrlSetPos(_WinAPI_GetDlgCtrlID($hTV[0]), 20, 48, $WT, $HT)
			GUICtrlSetPos(_WinAPI_GetDlgCtrlID($hTV[1]), $WT + 40, 48, $WC - $WT - 60, $HT)
			GUICtrlSetPos(_WinAPI_GetDlgCtrlID($hTV[2]), 20, $HT + 96, $WC - 40, $HC - $HT - 116)
			GUICtrlSetPos($Input[0], 20, 20, $WT)
			GUICtrlSetPos($Input[1], $WT + 40, 20, $WC - $WT - 60)
			GUICtrlSetPos($Input[2], 20, $HT + 68, $WC - 40)
			For $i = 0 To 2
				_TVSetPath($Input[$i], _GUICtrlTVExplorer_GetSelected($hTV[$i]))
			Next
			Return 0
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_SIZE

Скриншот:

TVExplorer.png

Источник: TVExplorer UDF (оффициальный форум)
Автор: Yashied
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Обнаружен небольшой баг: возможен вылет скрипта при изменении размеров GUI. Это связано с функцией _WinAPI_PathCompactPath() из библиотеки WinAPEx. Просто замените в этой функции

Код:
$tPath = DllStructCreate('wchar[' & (StringLen($sPath) + 1) & ']')


на

Код:
$tPath = DllStructCreate('wchar[' & (StringLen($sPath) + 32) & ']')


И все будет OK. В версии 3.2 это будет исправлено.

:smile:
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,323
Yashied
Как я понял, стиль $TVS_CHECKBOXES занесен в исключения. А почему? Я его попробовал "прикрутить" к стилю -1, вроде работает.
 

dronet

Знающий
Сообщения
46
Репутация
8
Yashied
Вот всяких прибамбасов навалом :smile: А такой библиотеки так не-хватало. :ok:
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
madmasles сказал(а):
Как я понял, стиль $TVS_CHECKBOXES занесен в исключения. А почему? Я его попробовал "прикрутить" к стилю -1, вроде работает.

Поправил.

И еще добавил дополнительные флаги:

TV_FLAG_SHOWFILESEXTENSION
TV_FLAG_SHOWFOLDERICON
TV_FLAG_SHOWSYSTEM
TV_FLAG_SHOWLIKEEXPLORER (параметры беруться из Windows Explorer'а)
 

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Попытался использовать UDF в режиме Loop.
Не знаю насколько корректно,но весьма удобная UDF получилась.
Код:
#region *** INCLUDES ***
#include <WindowsConstants.au3>
#include <GuiConstantsEx.au3>
#Include <TVExplorer.au3>
#Include <[email protected]>
#Include <GuiMenu.au3>
#endregion

Global Enum $idOpen=1000, $idSave,  $idInfo
Global $Timer
$hForm = GUICreate('222', 600, 612, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX))
GUISetBkColor(0xC0C0B0)
GUISeticon(@WindowsDir & '\explorer.exe')

$hMenu = _GUICtrlMenu_CreatePopup ()
_GUICtrlMenu_InsertMenuItem ($hMenu, 0, "Open", $idOpen)
_GUICtrlMenu_InsertMenuItem ($hMenu, 1, "Save", $idSave)
_GUICtrlMenu_InsertMenuItem ($hMenu, 3, "", 0)
_GUICtrlMenu_InsertMenuItem ($hMenu, 3, "Info", $idInfo)

$Input = GUICtrlCreateInput('', 20, 30, 560, 19)
GUICtrlSetResizing(-1, BitOR($GUI_DOCKLEFT, $GUI_DOCKTOP, $GUI_DOCKRIGHT, $GUI_DOCKHEIGHT))
GUICtrlSetState(-1, $GUI_DISABLE)
$TV = _GUICtrlTVExplorer_Create('D:\', 20, 50, 560, 526, -1, $WS_EX_CLIENTEDGE, BitOR($TV_FLAG_SHOWFILES, $TV_FLAG_SHOWHIDDEN), '_TVEvent')
GUICtrlSetResizing(-1, $GUI_DOCKBORDERS)
$Label = GUICtrlCreateLabel('0.000', 80, 587, 90, 14)
GUICtrlSetResizing(-1, BitOR($GUI_DOCKLEFT, $GUI_DOCKBOTTOM, $GUI_DOCKSIZE))

GUISetState()

_GUICtrlTreeView_Expand($TV, _GUICtrlTreeView_GetFirstItem($TV))

While 1
   Switch _GUICtrlTVExplorer_GetMsg()
	  Case $GUI_EVENT_CLOSE
		 GUIDelete()
		 _GUICtrlTVExplorer_Destroy($TV)
		 Exit
	EndSwitch
WEnd

Func _TVEvent($hTV, $iMsg, $sPath, $hItem)
	Switch $iMsg
		Case $TV_NOTIFY_BEGINUPDATE
			GUISetCursor(1, 1)
			$Timer = TimerInit()
		Case $TV_NOTIFY_ENDUPDATE
			GUICtrlSetData($Label, StringFormat('%.3f sec', TimerDiff($Timer) / 1000))
			GUISetCursor(2, 0)
		Case $TV_NOTIFY_SELCHANGED
			_TVSetPath()
			If StringInStr(FileGetAttrib($sPath), 'D') Then Return
			ShellExecute($sPath)
		Case $TV_NOTIFY_DBLCLK
			ConsoleWrite($sPath & @CR)
		Case $TV_NOTIFY_RCLICK
			_GUICtrlMenu_TrackPopupMenu($hMenu, $hForm)
;~		Case $TV_NOTIFY_DELETINGITEM
	EndSwitch
 EndFunc   ;==>_TVEvent
 
 Func _TVSetPath()
	Local $hInput = GUICtrlGetHandle($Input)
	If _WinAPI_GetUDFVersion() < '3.2' Then
		GUICtrlSetData($Input, _WinAPI_PathCompactPath($hInput, _GUICtrlTVExplorer_GetSelected($TV), _WinAPI_GetClientWidth($hInput) - 2))
	Else
		GUICtrlSetData($Input, _WinAPI_PathCompactPath($hInput, _GUICtrlTVExplorer_GetSelected($TV), -2))
	EndIf
 EndFunc   ;==>_TVSetPath


Возможно имеет смысл разделить создание дерева и его корневого элемента.
чтобы дать возможность создать несколько корневых элементов.


Добавлено:
Сообщение автоматически объединено:

И еще :
Где-то проскальзывал стиль окна , устраняющий мелькание при его ресайзе. Может кто помнит ?
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
gregaz сказал(а):
Возможно имеет смысл разделить создание дерева и его корневого элемента.

Я как раз сейчас закончил обновление библиотеки. Теперь можно будет создавать сколько угодно TreeView Explorer'ов (до 65535 :smile:). Позже выложу, как закончу тестирование...

gregaz сказал(а):
Где-то проскальзывал стиль окна , устраняющий мелькание при его ресайзе. Может кто помнит ?

$WS_EX_COMPOSITED

В Windows 7 и без него ничего не мелькает.
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
gregaz сказал(а):
Да с ним стало намного лучше...

Одно плохо, кнопки в правом верхнем углу окна ("X" и т.д.) перестают подсвечиваться...

P.S

Не знаю, как это сделано в самой Windows, но можно включать этот стиль только при изменении размеров окна или наоборот, выключать при попадании курсора мыши на заголовок окна.
 

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Yashied [?]
Одно плохо, кнопки в правом верхнем углу окна ("X" и т.д.) перестают подсвечиваться...
Вроде у меня на XP этого не наблюдается :-\
И еще одно пожелание :
Надо бы завести возможность задания шаблона выбора типов файлов.
Я думаю это не составит трудности
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
gregaz сказал(а):
Вроде у меня на XP этого не наблюдается...

:shok:

Это что же, значит только у меня наблюдается на всех XP и 7 с выключенным Aero? Если у тебя стоит не классический стиль, то при наведении курсора мыши на кнопку закрытия окна или нажатии на нее, она не подсвечивается, т.е. не становится светлее или темнее.

gregaz сказал(а):
Надо бы завести возможность задания шаблона выбора типов файлов.

OK.
 

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
У меня на XP SP3 кнопки светлеют независимо установлен стиль $WS_EX_COMPOSITED или нет


Добавлено:
Сообщение автоматически объединено:

И еще одна тонкость.
В скрипте может понадобиться отдельная ф-ия $WM_NOTIFY
для собственных нужд, например при использовании дополнительно скажем ListView.
Установка ее под любым именем блокирует внутреннюю ф-ию TV_WM_NOTIFY.

Есть возможность избежать этого ?
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
gregaz сказал(а):
Есть возможность избежать этого?

Автоматически нет. AutoIt не поддерживает цепочки GUIRegisterMsg(), как, например, хуки. Пользователь должен будет писать так:

Код:
GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')

...

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)

	Local $Result = TV_WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)

	If $Result <> $GUI_RUNDEFMSG Then
		Return $Result
	EndIf

	...

EndFunc   ;==>WM_NOTIFY
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Обновил библиотеку до версии 1.0.

Список изменений:
  • Добавлена возможность создавать более одного TreeView Explorer'а (см. скриншот).
  • Добавлена возможность задать шаблон для отображения файлов.
  • Добавлены следующие флаги:

    TV_FLAG_SHOWFILEICON

  • Исправлено несколько незначительных ошибок.
  • Изменен пример.
 

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Попытался все же добавить корневую папку в дерево.
Ничего другого не нашел, как :
Код:
$sPath1="D:\"
$iIconIndex = _TV_AddIcon("",$sPath1)
 _GUICtrlTreeView_SetChildren($hTV[2], _GUICtrlTreeView_AddChild($hTV[2], 0, $sPath1,$iIconIndex,$iIconIndex), 1)

В принципе работает , но ...
Может имеет все же смысл отделить само создание дерева от создания корневой папки.
Скажем : иметь возможность создать пустое дерево,если $sRoot=""
Добавить ф-ию добавления корневой папки .

Еще Обрати внимание на 1-й пост : " необходимо будет вместо функции GUIGrtMsg() "


Добавлено:
Сообщение автоматически объединено:

И еще:
В описание ф-ии : _GUICtrlTVExplorer_Create()
стоит добавить поддерживаемый формат задания шаблона для отображения файлов.
Скажем такой формат : "Images (*.jpg;*.bmp)", , как у FileOpenDialog ведь не поддерживается
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Yashied [?]
Не совсем понял, что ты имеешь в виду, точнее совсем не понял.

Получилось создание пустого дерева , путем задания несуществующего $sPath
Код:
$hTV[1] = _GUICtrlTVExplorer_Create("111", 360, 48, 320, 310, -1, $WS_EX_CLIENTEDGE, -1, '_TVEvent')

Теперь в него можно вставить нужные папки
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
TreeView Explorer может отображать только существующие папки. Если папка была удалена с диска, то она исчезнет из TreeView при выделении соответствующего элемента. Если была удалена корневая папка, то TreeView окажется пустым. Да, конечно можно напихать сколько угодно несвязанных папок (и это даже будет работать), но при этом возникнут проблемы при получении полного пути к выбранному элементу дерева. Параметр $tvData[i][8] является основным для всех внутренних функций, и именно на него нужно опираться при получении полного пути.

P.S

Параметр $iIndex во всех функциях является ID TreeView Explorer'а, или, другими словами, номером в массиве $tvData, начиная с 1.
 
Верх