Page 1 of 2

TV_DragAndDrop - Drag & Drop function for TreeView controls (Updated Nov, 13, 2020)

Posted: 20 Oct 2020, 18:45
by Pulover
Usage:
  • Call TV_Drag() from the TreeView's G-Label when A_GuiEvent contains "D" or "d". A line will show across the TreeView while holding the button to indicate the destination where the selected node will be dropped with its children.
  • If you point the mouse cursor to the half bottom part of the node text it will be dropped as a child of the pointed node. If you point it to the upper part it will drop it as sibling right below the pointed node.
  • TV_Drag() returns the target node id (if valid) which you can use to call TV_Drop() and effectively move the selection. Alternatively you can set AutoDrop option on as a shorthand.
  • Separating the Drag and Drop calls allows to check if the returned destination is a valid node to drop in as well as setting GuiControl, -Redraw to avoid flickering.
  • TV_Drop() may be called directly to move or copy nodes programmatically. You may pass the TreeView control's hwnd to keep icons and set Copy parameter to true if you want to copy nodes instead of moving.
:arrow: Sources, documentation and examples on GitHub

See also LV_Rows

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 21 Oct 2020, 02:17
by guest3456
outstanding

Update

Posted: 21 Oct 2020, 16:31
by Pulover
  • Updated TV_Drop() to return the ID of the created top node.

guest3456 wrote:
21 Oct 2020, 02:17
outstanding
Thanks! :D

Update [Fix]

Posted: 21 Oct 2020, 18:51
by Pulover
  • Fixed children being moved in reverse order.
  • Fixed items being dropped as first child instead of last.

Update

Posted: 22 Oct 2020, 08:38
by Pulover
  • Added DragButton parameter to TV_Drag().
  • Added Hwnd and Copy parameters to TV_Drop().

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 23 Oct 2020, 05:12
by Ahk_fan
:bravo: :bravo: Thank you for this solution.

Update

Posted: 29 Oct 2020, 07:34
by Pulover
  • Added FirstChild parameter in TV_Drop() to allow drop as first/top sibling.

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 29 Oct 2020, 13:38
by burque505
@Pulover, thanks a million for this. I have an observation about today's release: Once an item is demoted by DragAndDrop (on Win7 and Win10), it is quite difficult (impossible?) to promote it again. In the TV_Drag_Demo script, try the following.

1) You have this when the script starts.
one.PNG
one.PNG (16.55 KiB) Viewed 2324 times
2) Drag the Second Parent to be a child of First Parent.
two.PNG
two.PNG (18.08 KiB) Viewed 2324 times
Try to promote Second Parent again so that it is, once again, a sibling of First Parent instead of a child (i.e., a level one item). My first thought was to drag First Parent below Second Parent, but that can't be done.

Thanks again for this and all your other generous contributions.
Regards,
burque505

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 29 Oct 2020, 15:59
by Pulover
You're welcome, @burque505.

In fact it's not only possible, but quite easy to do. Maybe you've missed this part:
If you point it to the upper part it will drop it as sibling right below the pointed node.

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 29 Oct 2020, 16:11
by burque505
@Pulover, thanks a million. :facepalm: What a relief. I wasn't dragging the cursor far enough over to the left. I see now that the indicator line has to extend all the way to the left of the GUI to promote an item to Level One.
Regards, burque505

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 30 Oct 2020, 07:50
by hasantr
Thank you. As always, this work is great.

Thanks for the

Code: Select all

GetIcon()
Function. I was using a devious solution like creating one extension in the temp folder for each format.

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 30 Oct 2020, 17:56
by hasantr

Code: Select all

Paths :=
(
"D:\_AppData_\
D:\_AppData_\Desktop\
D:\_AppData_\Desktop\TEST\
D:\_AppData_\Desktop\TEST\TEST1\
D:\_AppData_\Desktop\TEST\TEST1\TEST 1-1\
D:\_AppData_\Desktop\TEST\TEST1\TEST 1-1\TEST 1-1-1\
D:\_AppData_\Desktop\TEST\TEST1\TEST 1-2\
D:\_AppData_\Desktop\TEST\TEST2\
D:\_AppData_\Desktop\TEST\TEST2\TEST 2-1\"
)
How is it practical to add such a list of folders that are not clear whether they are on the disk or not. I don't want them checked on disk. They just need to be added in the Tree view.

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 30 Oct 2020, 18:10
by burque505
@hasantr, take a look at the "TreeView Browser.ahk" file in the Examples folder. You will find a "CreateTreeView(TreeViewDefinitionString)" function by @Learning one in the script. Using your "Paths" variable described above as an argument to the function, you should be able to create your treeview.
Regards,
burque505

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 30 Oct 2020, 18:17
by hasantr
burque505 wrote:
30 Oct 2020, 18:10
@hasantr, take a look at the "TreeView Browser.ahk" file in the Examples folder. You will find a "CreateTreeView(TreeViewDefinitionString)" function by @Learning one in the script. Using your "Paths" variable described above as an argument to the function, you should be able to create your treeview.
Regards,
burque505
My attempts have failed.
Actually, I've been trying to do this for a long time. I wanted to ask here if there is a Function I missed.

Maybe I need to sleep now. :)

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 30 Oct 2020, 18:21
by Pulover
@hasantr, you should try the Save File button and check the format of the saved file. You might want to modify the LoadFile label to convert your format to the one expected by CreateTreeView(). The purpose of TreeView Browser was exactly to browse my files from another computer back when I wrote it.

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 30 Oct 2020, 18:25
by hasantr
Thanks I will do this after I get my sleep. If I can come up with a solution that looks good I'll put it here.

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 31 Oct 2020, 04:47
by hasantr
Pulover wrote:
30 Oct 2020, 18:21
@hasantr, you should try the Save File button and check the format of the saved file. You might want to modify the LoadFile label to convert your format to the one expected by CreateTreeView(). The purpose of TreeView Browser was exactly to browse my files from another computer back when I wrote it.
I've created a solution, if not very good. I hope it works for someone in need.
Thanks again.

Code: Select all

Paths :=
(
"C:\Users\hasan\Desktop\
C:\Users\hasan\Desktop\WhatsApp
C:\Users\hasan\Desktop\WhatsApp\Media\WhatsApp Documents\
C:\Users\hasan\Desktop\test\
D:\TestIndex
D:\_AppData_\Desktop
D:\_AppData_\Desktop\AHK TEST\UDFS 7ZDLL İLE
D:\_AppData_\Desktop\AHK TEST\UDFS 7ZDLL İLE\BüyükUdfLer1
D:\_AppData_\Desktop\AHK TEST\UDFS 7ZDLL İLE\UDFLER"
)

Clipboard := PathListToTree(Paths)
PathListToTree(Paths){
	Paths := StrSplit(Paths,"`n")
	TO := {}
	For, K,Dir in Paths
	{	
		if(Dir == "")
			Continue
		Dir := SubStr(Dir,StrLen(Dir),1) = "\" ? SubStr(Dir,1,StrLen(Dir) - 1) : Dir ;Remove last character if "\"
		PATH := Dir
		PathBack  :=
		Loop 125 ; NO MORE "\"
		{
			SplitPath,PATH,,PATH
			if(TO.HasKey(PATH) == true){ ; this has a parent directory
				TO[Dir] := TO[PATH] + 1
				break
			}
			if(PathBack == PATH){ ; the loop should end as there are no new subdirectories left. This is the root directory
				TO[Dir] :=  1
				Break
			}
			PathBack := PATH
		}
		Loop, % TO[Dir]
			Stack .= "`t"
		Stack .= Dir . (A_Index != Paths.MaxIndex() ? "`n" : "")
	}
	return Stack
}

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 01 Nov 2020, 12:02
by hasantr
@Pulover I wanted to use the GetIcon() function, but is there a problem? It takes an infinite number of icons. For example, if I call 5 PDF extensions, it returns 5 separate icon numbers. I couldn't figure out where the problem was caused.

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 01 Nov 2020, 16:46
by Pulover
hasantr wrote:
01 Nov 2020, 12:02
@Pulover I wanted to use the GetIcon() function, but is there a problem? It takes an infinite number of icons. For example, if I call 5 PDF extensions, it returns 5 separate icon numbers. I couldn't figure out where the problem was caused.
I don't remember writing that function... probably copied it from somewhere in the forum. But you're right, there is problem with it. Must have been my mistake when I modified it. Here's a fixed version:

Code: Select all

GetIcon(FileName, ImageListID)
{
	static IconArray := []

	sfi_size := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340)
	VarSetCapacity(sfi, sfi_size)
	SplitPath, FileName,,, FileExt
	if FileExt in EXE,ICO,ANI,CUR
	{
		ExtID := FileExt
		IconNumber = 0
	}
	else
	{
		ExtID = 0
		Loop 7
		{
			StringMid, ExtChar, FileExt, A_Index, 1
			If not ExtChar
				break
			ExtID := ExtID | (Asc(ExtChar) << (8 * (A_Index - 1)))
		}
		IconNumber := IconArray[ExtID]
	}
	If not IconNumber
	{
		if not DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), "str",  "." FileExt
			, "uint", (FileExt ? 0x80 : 0), "ptr", &sfi, "uint", sfi_size, "uint", (FileExt ? 0x111 : 0x101))
			IconNumber = 9999999
		else
		{
			hIcon := NumGet(sfi, 0)
			IconNumber := DllCall("ImageList_ReplaceIcon", "ptr", ImageListID, "int", -1, "ptr", hIcon) + 1
			DllCall("DestroyIcon", "ptr", hIcon)
			IconArray[ExtID] := IconNumber
		}
	}
	return IconNumber
}

Re: TV_DragAndDrop - Drag & Drop function for TreeView controls

Posted: 01 Nov 2020, 18:34
by hasantr
Pulover wrote:
01 Nov 2020, 16:46
hasantr wrote:
01 Nov 2020, 12:02
@Pulover I wanted to use the GetIcon() function, but is there a problem? It takes an infinite number of icons. For example, if I call 5 PDF extensions, it returns 5 separate icon numbers. I couldn't figure out where the problem was caused.
I don't remember writing that function... probably copied it from somewhere in the forum. But you're right, there is problem with it. Must have been my mistake when I modified it. Here's a fixed version:

Code: Select all

GetIcon(FileName, ImageListID)
{
	static IconArray := []

	sfi_size := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340)
	VarSetCapacity(sfi, sfi_size)
	SplitPath, FileName,,, FileExt
	if FileExt in EXE,ICO,ANI,CUR
	{
		ExtID := FileExt
		IconNumber = 0
	}
	else
	{
		ExtID = 0
		Loop 7
		{
			StringMid, ExtChar, FileExt, A_Index, 1
			If not ExtChar
				break
			ExtID := ExtID | (Asc(ExtChar) << (8 * (A_Index - 1)))
		}
		IconNumber := IconArray[ExtID]
	}
	If not IconNumber
	{
		if not DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), "str",  "." FileExt
			, "uint", (FileExt ? 0x80 : 0), "ptr", &sfi, "uint", sfi_size, "uint", (FileExt ? 0x111 : 0x101))
			IconNumber = 9999999
		else
		{
			hIcon := NumGet(sfi, 0)
			IconNumber := DllCall("ImageList_ReplaceIcon", "ptr", ImageListID, "int", -1, "ptr", hIcon) + 1
			DllCall("DestroyIcon", "ptr", hIcon)
			IconArray[ExtID] := IconNumber
		}
	}
	return IconNumber
}
Thanks. I tried Static array. "IconArray[ExtID]" I skipped the fix. :bravo: